﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Записывает настройку версионирования объекта.
//
// Параметры:
//  ТипОбъекта - Строка
//             - Тип
//             - ОбъектМетаданных
//             - СправочникСсылка.ИдентификаторыОбъектовМетаданных - объект метаданных;
//  ВариантВерсионирования - ПеречислениеСсылка.ВариантыВерсионированияОбъектов - условие записи версий;
//  СрокХраненияВерсий - ПеречислениеСсылка.СрокиХраненияВерсий - срок, после которого версии подлежат очистке.
//
Процедура ЗаписатьНастройкуВерсионированияПоОбъекту(Знач ТипОбъекта, Знач ВариантВерсионирования, Знач СрокХраненияВерсий = Неопределено) Экспорт
	
	Если ТипЗнч(ТипОбъекта) <> Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") Тогда
		ТипОбъекта = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ТипОбъекта);
	КонецЕсли;
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных();
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НастройкиВерсионированияОбъектов");
		ЭлементБлокировки.УстановитьЗначение("ТипОбъекта", ТипОбъекта);
		Блокировка.Заблокировать();
		
		Настройка = РегистрыСведений.НастройкиВерсионированияОбъектов.СоздатьМенеджерЗаписи();
		Настройка.ТипОбъекта = ТипОбъекта;
		
		Если СрокХраненияВерсий = Неопределено Тогда
			Настройка.Прочитать();
			Если Настройка.Выбран() Тогда
				СрокХраненияВерсий = Настройка.СрокХраненияВерсий;
			Иначе
				Настройка.ТипОбъекта = ТипОбъекта;
				СрокХраненияВерсий = Перечисления.СрокиХраненияВерсий.Бессрочно;
			КонецЕсли;
		КонецЕсли;
		
		Настройка.СрокХраненияВерсий = СрокХраненияВерсий;
		Настройка.Вариант = ВариантВерсионирования;
		Настройка.Записать();
		ЗафиксироватьТранзакцию();
		
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Выполняет с формой действия, необходимые для подключения подсистемы версионирования.
//
// Параметры:
//  Форма - ФормаКлиентскогоПриложения - форма для подключения механизма версионирования.
//
Процедура ПриСозданииНаСервере(Форма) Экспорт
	
	ПолноеИмяМетаданных = Неопределено;
	Если ЕстьПравоЧтенияДанныхВерсийОбъектов() И ПолучитьФункциональнуюОпцию("ИспользоватьВерсионированиеОбъектов") Тогда
		ИмяФормыМассив = СтрРазделить(Форма.ИмяФормы, ".", Ложь);
		ПолноеИмяМетаданных = ИмяФормыМассив[0] + "." + ИмяФормыМассив[1];
	КонецЕсли;
	
	Объект = Неопределено;
	Если ПолноеИмяМетаданных <> Неопределено Тогда
		Объект = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПолноеИмяМетаданных);
	КонецЕсли;
	
	Форма.УстановитьПараметрыФункциональныхОпцийФормы(Новый Структура("ТипВерсионируемогоОбъекта", Объект));
	
КонецПроцедуры

// Возвращает признак использования версионирования для указанного объекта метаданных.
//
// Параметры:
//  ИмяОбъекта - Строка - полный путь к объекту метаданных. Например, "Справочник.Номенклатура".
//
// Возвращаемое значение:
//  Булево - Истина, если включено.
//
Функция ВключеноВерсионированиеОбъекта(ИмяОбъекта) Экспорт
	СписокОбъектов = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ИмяОбъекта);
	Возврат ВключеноВерсионированиеОбъектов(СписокОбъектов)[ИмяОбъекта];
КонецФункции

// Возвращает признак использования версионирования для списка объектов.
//
// Параметры:
//  СписокОбъектов - Массив - список имен объектов метаданных.
//
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ - Строка - имя объекта метаданных.
//   * Значение - Булево - включено или выключено версионирование.
//
Функция ВключеноВерсионированиеОбъектов(СписокОбъектов) Экспорт
	
	СоответствиеТипов = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(СписокОбъектов);
	ТипыОбъектов = Новый Массив;
	Для Каждого Элемент Из СоответствиеТипов Цикл
		ТипыОбъектов.Добавить(Элемент.Значение);
	КонецЦикла;
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ИдентификаторыОбъектовМетаданных.ПолноеИмя КАК ИмяОбъекта,
	|	ЕСТЬNULL(НастройкиВерсионированияОбъектов.Использовать, ЛОЖЬ) КАК ВключеноВерсионирование
	|ИЗ
	|	Справочник.ИдентификаторыОбъектовМетаданных КАК ИдентификаторыОбъектовМетаданных
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиВерсионированияОбъектов КАК НастройкиВерсионированияОбъектов
	|		ПО НастройкиВерсионированияОбъектов.ТипОбъекта = ИдентификаторыОбъектовМетаданных.Ссылка
	|ГДЕ
	|	ИдентификаторыОбъектовМетаданных.Ссылка В(&ТипыОбъектов)";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("ТипыОбъектов", ТипыОбъектов);
	
	Результат = Новый Соответствие;
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Результат.Вставить(Выборка.ИмяОбъекта, Выборка.ВключеноВерсионирование);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Включает запись истории изменения для указанного объекта метаданных.
//
// Параметры:
//  ИмяОбъекта - Строка - полный путь к объекту метаданных. Например, "Справочник.Номенклатура".
//  ВариантВерсионирования - ПеречислениеСсылка.ВариантыВерсионированияОбъектов - вариант версионирования объекта.
//
Процедура ВключитьВерсионированиеОбъекта(ИмяОбъекта, Знач ВариантВерсионирования = Неопределено) Экспорт
	
	Если ВариантВерсионирования = Неопределено Тогда
		ВариантВерсионирования = Перечисления.ВариантыВерсионированияОбъектов.ВерсионироватьПриЗаписи;
	КонецЕсли;
	
	Если ТипЗнч(ВариантВерсионирования) = Тип("Строка") Тогда
		Если Метаданные.Перечисления.ВариантыВерсионированияОбъектов.ЗначенияПеречисления.Найти(ВариантВерсионирования) <> Неопределено Тогда
			ВариантВерсионирования = Перечисления.ВариантыВерсионированияОбъектов[ВариантВерсионирования];
		КонецЕсли;
	КонецЕсли;
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Неизвестный вариант версионирования: ""%1""'"), ВариантВерсионирования);
	ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(ВариантВерсионирования) = Тип("ПеречислениеСсылка.ВариантыВерсионированияОбъектов"),
		ТекстОшибки, "ВерсионированиеОбъектов.ВключитьВерсионированиеОбъекта");
		
	ЗаписатьНастройкуВерсионированияПоОбъекту(ИмяОбъекта, ВариантВерсионирования);

КонецПроцедуры

// Включает запись истории изменения для указанных объектов метаданных.
//
// Параметры:
//  Объекты - Соответствие из КлючИЗначение - объекты, для которых надо включить версионирование:
//   * Ключ    - Строка - полный путь к объекту метаданных. Например, "Справочник.Номенклатура".
//   * Значение - ПеречислениеСсылка.ВариантыВерсионированияОбъектов - вариант версионирования объекта.
//
Процедура ВключитьВерсионированиеОбъектов(Объекты) Экспорт
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных();
		Блокировка.Добавить("РегистрСведений.НастройкиВерсионированияОбъектов");
		Блокировка.Заблокировать();

		Для Каждого ИмяОбъекта Из Объекты Цикл
			ЗаписатьНастройкуВерсионированияПоОбъекту(ИмяОбъекта.Ключ, Перечисления.ВариантыВерсионированияОбъектов.ВерсионироватьПриЗаписи);
		КонецЦикла;
		ЗафиксироватьТранзакцию();

	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Возвращает признак хранения истории для формы настроек версионирования объекта.
//
// Возвращаемое значение: 
//   Булево
//
// Пример:
//	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВерсионированиеОбъектов") Тогда
//		МодульВерсионированиеОбъектов = ОбщегоНазначения.ОбщийМодуль("ВерсионированиеОбъектов");
//		ИспользоватьВерсионированиеОбъектов = МодульВерсионированиеОбъектов.ЗначениеФлажкаХранитьИсторию();
//	Иначе 
//		Элементы.ГруппаУправлениеВерсионированиемОбъектов.Видимость = Ложь;
//	КонецЕсли;
//
Функция ЗначениеФлажкаХранитьИсторию() Экспорт
	
	Возврат ПолучитьФункциональнуюОпцию("ИспользоватьВерсионированиеОбъектов");
	
КонецФункции

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

// Записывает версию объекта в информационную базу.
//
// Параметры:
//  Источник - СправочникОбъект, ДокументОбъект - записываемый объект ИБ;
//  РежимЗаписи - РежимЗаписиДокумента.
//
Процедура ЗаписатьВерсиюОбъекта(Знач Источник, РежимЗаписи = Неопределено) Экспорт
	
	// Безусловная проверка на ОбменДанными.Загрузка не требуется, т.к. в момент записи
	// версионируемого объекта при обмене необходимо сохранить его текущую версию в истории версий.
	Если Не ПолучитьФункциональнуюОпцию("ИспользоватьВерсионированиеОбъектов") Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ЗначениеСсылочногоТипа(Источник) Тогда
		Источник = Источник.ПолучитьОбъект();
	КонецЕсли;
	
	Если Источник = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ОбменДанными.Загрузка
		И Источник.ДополнительныеСвойства.Свойство("ПропуститьЗаписьВерсииОбъекта")
		И ПривилегированныйРежим() Тогда
		Возврат;
	КонецЕсли;
	
	Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Если Не Источник.Ссылка.Пустая() Тогда
			ЗаписатьДанныеТекущейВерсии(Источник.Ссылка, Истина);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Если ВыполняетсяЗаписьОбъекта() Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ДополнительныеСвойства.Свойство("СведенияОВерсииОбъекта") Тогда
		Возврат;
	КонецЕсли;
	
	ПриСозданииВерсииОбъекта(Источник, РежимЗаписи);
	
КонецПроцедуры

// Записывает в информационную базу версию объекта, полученного при обмене данными.
//
// Параметры:
//  Объект - СправочникОбъект, ДокументОбъект - записываемый объект.
//  СведенияОВерсииОбъекта - Структура - содержит информацию о версии объекта.
//  СсылкаСуществует - Булево - признак наличия объекта по ссылке в информационной базе.
//
Процедура СоздатьВерсиюОбъектаПоОбменуДанными(Объект, СведенияОВерсииОбъекта, СсылкаСуществует, Отправитель) Экспорт
	
	Ссылка = Объект.Ссылка;
	
	Если Не ЗначениеЗаполнено(СсылкаСуществует) Тогда
		СсылкаСуществует = ОбщегоНазначения.СсылкаСуществует(Ссылка);
	КонецЕсли;
	
	ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта[СведенияОВерсииОбъекта.ТипВерсииОбъекта];
	
	Если СсылкаСуществует Тогда
		Если ОбъектВерсионируется(Объект) И РегистрВерсийВходитВСоставПланаОбмена(Отправитель) Тогда
			Возврат;
		КонецЕсли;
	Иначе
		Ссылка = ОбщегоНазначения.МенеджерОбъектаПоСсылке(Ссылка).ПолучитьСсылку(Объект.ПолучитьСсылкуНового().УникальныйИдентификатор());
	КонецЕсли;
	НомерПоследнейВерсии = НомерПоследнейВерсии(Ссылка);
	
	СведенияОВерсииОбъекта.Вставить("Объект", Ссылка);
	СведенияОВерсииОбъекта.Вставить("НомерВерсии", Число(НомерПоследнейВерсии) + 1);
	СведенияОВерсииОбъекта.ТипВерсииОбъекта = ТипВерсииОбъекта;
	
	Если Не ЗначениеЗаполнено(СведенияОВерсииОбъекта.АвторВерсии) Тогда
		СведенияОВерсииОбъекта.АвторВерсии = Пользователи.АвторизованныйПользователь();
	КонецЕсли;
	
	СоздатьВерсиюОбъекта(Объект, СведенияОВерсииОбъекта, Ложь);
	
КонецПроцедуры

// Устанавливает признак игнорирования версии объекта.
//
// Параметры:
//  Ссылка - ЛюбаяСсылка - ссылка на игнорируемый объект.
//  НомерВерсии - Число - номер версии игнорируемого объекта.
//  Игнорировать - Булево - признак игнорирования версии.
//
Процедура ИгнорироватьВерсиюОбъекта(Ссылка, НомерВерсии, Игнорировать) Экспорт
	
	ПроверитьНаличиеПравНаИзменениеОбъекта(Ссылка.Метаданные());
	
	УстановитьПривилегированныйРежим(Истина);
	
	НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.Объект.Установить(Ссылка);
	НаборЗаписей.Отбор.НомерВерсии.Установить(НомерВерсии);
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ВерсииОбъектов");
	ЭлементБлокировки.УстановитьЗначение("Объект", Ссылка);
	ЭлементБлокировки.УстановитьЗначение("НомерВерсии", НомерВерсии);
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		НаборЗаписей.Прочитать();
		Запись = НаборЗаписей[0];
		Запись.ВерсияПроигнорирована = Игнорировать;
		НаборЗаписей.Записать();
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Процедура ИзменитьПредупреждениеСинхронизации(ПараметрыЗаписиРегистра, ПроверитьНаличиеЗаписи) Экспорт
	Перем Ссылка, НомерВерсии;
	
	ПараметрыЗаписиРегистра.Свойство("Ссылка", Ссылка);
	ПараметрыЗаписиРегистра.Свойство("НомерВерсии", НомерВерсии);
	
	Если Ссылка = Неопределено
		ИЛИ НомерВерсии = Неопределено Тогда
		
		Возврат;
		
	КонецЕсли;
	
	ПроверитьНаличиеПравНаИзменениеОбъекта(Ссылка.Метаданные());
	УстановитьПривилегированныйРежим(Истина);
	
	ИменаОбновляемыхПолей = "";
	Для каждого ЭлементСтруктуры Из ПараметрыЗаписиРегистра Цикл
		
		Если СтрНайти("Ссылка,НомерВерсии", ЭлементСтруктуры.Ключ) <> 0 Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		ИменаОбновляемыхПолей = ИменаОбновляемыхПолей + "," + ЭлементСтруктуры.Ключ;
		
	КонецЦикла;
	
	ИменаОбновляемыхПолей = СОКРЛП(Сред(ИменаОбновляемыхПолей, 2));
	Если ПустаяСтрока(ИменаОбновляемыхПолей) Тогда
		
		Возврат;
		
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ВерсииОбъектов");
	ЭлементБлокировки.УстановитьЗначение("Объект", Ссылка);
	ЭлементБлокировки.УстановитьЗначение("НомерВерсии", НомерВерсии);
	
	НачатьТранзакцию();
	Попытка
		
		Блокировка.Заблокировать();
		
		МенеджерЗаписи = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.Объект = Ссылка;
		МенеджерЗаписи.НомерВерсии = НомерВерсии;
		
		МенеджерЗаписи.Прочитать(); // читаем для сохранения реквизитов, которые не передаем на форму
		Если НЕ МенеджерЗаписи.Выбран() Тогда
			
			// Сценарий: открыли карточку предупреждения, а параллельно поправили проблему
			ОтменитьТранзакцию();
			Возврат;
			
		КонецЕсли;
	
		ЗаполнитьЗначенияСвойств(МенеджерЗаписи, ПараметрыЗаписиРегистра, ИменаОбновляемыхПолей);
		МенеджерЗаписи.Записать(Истина);
		
		ЗафиксироватьТранзакцию();
		
	Исключение
		
		ОтменитьТранзакцию();
		ВызватьИсключение;
		
	КонецПопытки;
	
КонецПроцедуры

// Возвращает количество коллизий или непринятых объектов.
//
// Параметры:
//  УзлыОбмена - ПланОбменаСсылка
//             - Массив
//             - СписокЗначений
//             - Неопределено - отбор для получения количества коллизий.
//  ЭтоКоличествоКоллизий - Булево - если Истина, то возвращает количество коллизий, иначе количество непринятых.
//  ПоказыватьПроигнорированные - Булево - признак необходимости учета проигнорированных.
//  УзелИнформационнойБазы - ПланОбменаСсылка - отбор по конкретному узлу.
//  Период - СтандартныйПериод - отбор по периоду.
//  СтрокаПоиска - Строка - отбор по комментарию.
//
Функция КоличествоКоллизийИлиНепринятых(УзлыОбмена, ЭтоКоличествоКоллизий,
	ПоказыватьПроигнорированные, Период, СтрокаПоиска) Экспорт
	
	Количество = 0;
	
	Если Не ЕстьПравоЧтенияИнформацииОВерсияхОбъектов() Тогда
		Возврат Количество;
	КонецЕсли;
	
	ТекстЗапроса = 
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	КОЛИЧЕСТВО(ВерсииОбъектов.Объект) КАК Количество
		|ИЗ
		|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
		|ГДЕ
		|	ВерсииОбъектов.ВерсияПроигнорирована <> &ОтборПоПропущенным
		|	И ВерсииОбъектов.ТипВерсииОбъекта В(&ТипыВерсий)
		|	И &ОтборПоУзлу
		|	И &ОтборПоПериоду
		|	И &ОтборПоПричине";
	
	Запрос = Новый Запрос;
	
	ОтборПоПропущенным = ?(ПоказыватьПроигнорированные, Неопределено, Истина);
	Запрос.УстановитьПараметр("ОтборПоПропущенным", ОтборПоПропущенным);
	
	Если УзлыОбмена = Неопределено Тогда
		СтрокаОтбора = "ИСТИНА";
	ИначеЕсли ПланыОбмена.ТипВсеСсылки().СодержитТип(ТипЗнч(УзлыОбмена)) Тогда
		СтрокаОтбора = "ВерсииОбъектов.АвторВерсии = &УзлыОбмена";
		Запрос.УстановитьПараметр("УзлыОбмена", УзлыОбмена);
	Иначе
		СтрокаОтбора = "ВерсииОбъектов.АвторВерсии В (&УзлыОбмена)";
		Запрос.УстановитьПараметр("УзлыОбмена", УзлыОбмена);
	КонецЕсли;
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоУзлу", СтрокаОтбора);
	
	Если ЗначениеЗаполнено(Период) Тогда
		СтрокаОтбора = "(ВерсииОбъектов.ДатаВерсии >= &ДатаНачала
		| И ВерсииОбъектов.ДатаВерсии <= &ДатаОкончания)";
		Запрос.УстановитьПараметр("ДатаНачала", Период.ДатаНачала);
		Запрос.УстановитьПараметр("ДатаОкончания", Период.ДатаОкончания);
	Иначе
		СтрокаОтбора = "ИСТИНА";
	КонецЕсли;
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоПериоду", СтрокаОтбора);
	
	ТипыВерсий = Новый СписокЗначений;
	Если ЗначениеЗаполнено(ЭтоКоличествоКоллизий) Тогда
		
		Если ЭтоКоличествоКоллизий Тогда
			ТипыВерсий.Добавить(Перечисления.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии);
			ТипыВерсий.Добавить(Перечисления.ТипыВерсийОбъекта.НепринятыеДанныеПоКоллизии);
			СтрокаОтбора = "ИСТИНА";
		Иначе
			ТипыВерсий.Добавить(Перечисления.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе);
			ТипыВерсий.Добавить(Перечисления.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе);
			
			Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
				СтрокаОтбора = 
					"Выразить(ВерсииОбъектов.Комментарий КАК Строка(1000)) ПОДОБНО &Комментарий СПЕЦСИМВОЛ ""~""
					|ИЛИ Выразить(ВерсииОбъектов.ПредупреждениеСинхронизации КАК Строка(1000)) ПОДОБНО &Комментарий СПЕЦСИМВОЛ ""~""";
				Запрос.УстановитьПараметр("Комментарий", 
					"%" + ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(СокрЛП(Лев(СтрокаПоиска, 998))) + "%");
			Иначе
				СтрокаОтбора = "ИСТИНА";
			КонецЕсли;
		КонецЕсли;
		
	Иначе // Отбор по комментарию не поддерживается.
		ТипыВерсий.Добавить(Перечисления.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии);
		ТипыВерсий.Добавить(Перечисления.ТипыВерсийОбъекта.НепринятыеДанныеПоКоллизии);
		ТипыВерсий.Добавить(Перечисления.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе);
		ТипыВерсий.Добавить(Перечисления.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе);
	КонецЕсли;
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоПричине", СтрокаОтбора);
	Запрос.УстановитьПараметр("ТипыВерсий", ТипыВерсий);
	
	Запрос.Текст = ТекстЗапроса;
	Результат = Запрос.Выполнить();
	
	Если Не Результат.Пустой() Тогда
		
		Выборка = Результат.Выбрать();
		Выборка.Следующий();
		Количество = Выборка.Количество;
	КонецЕсли;
	
	Возврат Количество;
	
КонецФункции

Функция АктуализироватьИнформациюОПроблемахВерсийСинхронизацииДанных(УзлыСинхронизации) Экспорт
	
	Если Не ЕстьПравоЧтенияИнформацииОВерсияхОбъектов() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("УзлыСинхронизации", УзлыСинхронизации);
	
	Запрос.Текст =
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 101
	|	1 КАК КоличествоПредупрежденийВерсий
	|ПОМЕСТИТЬ ВременнаяТаблица
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	НЕ ВерсииОбъектов.ВерсияПроигнорирована
	|	И ВерсииОбъектов.АвторВерсии В (&УзлыСинхронизации)
	|	И ВерсииОбъектов.ТипВерсииОбъекта В (ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии),
	|		ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыеДанныеПоКоллизии),
	|		ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе),
	|		ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе))
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ЕСТЬNULL(СУММА(1), 0) КАК КоличествоПредупрежденийВерсий
	|ИЗ
	|	ВременнаяТаблица КАК ВременнаяТаблица";
	
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		
		Возврат Выборка.КоличествоПредупрежденийВерсий;
		
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция ЕстьПравоЧтенияИнформацииОВерсияхОбъектов() Экспорт
	Возврат ПравоДоступа("Просмотр", Метаданные.РегистрыСведений.ВерсииОбъектов);
КонецФункции

Функция ЕстьПравоЧтенияДанныхВерсийОбъектов() Экспорт
	Возврат ПравоДоступа("Просмотр", Метаданные.ОбщиеКоманды.ИсторияИзменений);
КонецФункции

// Заполняет параметры динамического списка, отображающего проблемные версии объектов,
// созданные при получении данных в результате обмена данными в случае коллизий,
// либо в случае отказа от записи документов в результате непрохождения проверки по дате запрета изменения.
//
// Параметры:
//  Список - ДинамическийСписок - инициализируемый динамический список.
//  ВидПроблемы - Строка - коллизии - происходит инициализация списка коллизий,
//                         НепринятыеПоДате - непринятых по дате.
//
Процедура ИнициализацияДинамическогоСпискаПроблемныхВерсий(Список, ВидПроблемы = "Коллизии") Экспорт
	
	Если ВидПроблемы = "НепринятыеПоДате" Тогда
		ТекстЗапроса =
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	НепринятаяВерсия.ДатаВерсии КАК Дата,
		|	НепринятаяВерсия.Объект КАК Ссылка,
		|	НепринятаяВерсия.Комментарий КАК ПричинаЗапрета,
		|	ВЫБОР
		|		КОГДА НепринятаяВерсия.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе)
		|			ТОГДА ЛОЖЬ
		|		ИНАЧЕ ИСТИНА
		|	КОНЕЦ КАК НовыйОбъект,
		|	ЕСТЬNULL(НепринятаяВерсия.НомерВерсии, 0) КАК НомерДругойВерсии,
		|	НепринятаяВерсия.АвторВерсии КАК АвторДругойВерсии,
		|	ЕСТЬNULL(ТекущаяВерсия.НомерВерсии, 0) КАК НомерЭтойВерсии,
		|	ТИПЗНАЧЕНИЯ(НепринятаяВерсия.Объект) КАК ТипСтрокой,
		|	НепринятаяВерсия.ВерсияПроигнорирована КАК ВерсияПроигнорирована
		|ИЗ
		|	РегистрСведений.ВерсииОбъектов КАК НепринятаяВерсия
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВерсииОбъектов КАК ТекущаяВерсия
		|		ПО НепринятаяВерсия.Объект = ТекущаяВерсия.Объект
		|			И (НепринятаяВерсия.НомерВерсии = ТекущаяВерсия.НомерВерсии + 1)
		|ГДЕ
		|	НепринятаяВерсия.ТипВерсииОбъекта В (ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе),
		|		ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе))";
		
	ИначеЕсли ВидПроблемы = "Коллизии" Тогда
		ТекстЗапроса =
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	ВерсииДругойПрограммы.ДатаВерсии КАК Дата,
		|	ВерсииДругойПрограммы.Объект КАК Ссылка,
		|	ТИПЗНАЧЕНИЯ(ВерсииДругойПрограммы.Объект) КАК ТипСтрокой,
		|	ВерсииЭтойПрограммы.НомерВерсии КАК НомерЭтойВерсии,
		|	ВерсииДругойПрограммы.НомерВерсии КАК НомерДругойВерсии,
		|	ВерсииДругойПрограммы.АвторВерсии КАК АвторДругойВерсии,
		|	ВЫБОР
		|		КОГДА ВерсииДругойПрограммы.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии)
		|			ТОГДА ИСТИНА
		|		ИНАЧЕ ЛОЖЬ
		|	КОНЕЦ КАК ДругаяВерсияПринята,
		|	ВерсииДругойПрограммы.ВерсияПроигнорирована КАК ВерсияПроигнорирована
		|ИЗ
		|	РегистрСведений.ВерсииОбъектов КАК ВерсииДругойПрограммы
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВерсииОбъектов КАК ВерсииЭтойПрограммы
		|		ПО ВерсииДругойПрограммы.Объект = ВерсииЭтойПрограммы.Объект
		|			И (ВерсииДругойПрограммы.НомерВерсии = ВерсииЭтойПрограммы.НомерВерсии + 1)
		|ГДЕ
		|	ВерсииДругойПрограммы.ТипВерсииОбъекта В (ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии),
		|		ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НеПринятыеДанныеПоКоллизии))";
	КонецЕсли;
	
	Список.ТекстЗапроса = ТекстЗапроса;
	Список.ПроизвольныйЗапрос = Истина;
	Список.ОсновнаяТаблица = "РегистрСведений.ВерсииОбъектов";
	Список.ДинамическоеСчитываниеДанных = Истина;
	
КонецПроцедуры

Функция ТекстЗапросаСпискаПредупрежденияВерсий() Экспорт
	
	Возврат
	"ВЫБРАТЬ
	|	НепринятаяВерсия.АвторВерсии,
	|	НепринятаяВерсия.Объект,
	|	НЕОПРЕДЕЛЕНО,
	|	НепринятаяВерсия.ТипВерсииОбъекта,
	|	ВЫБОР
	|		КОГДА
	|			НепринятаяВерсия.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе)
	|			ТОГДА &НепринятыйСуществующий
	|		КОГДА
	|			НепринятаяВерсия.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе)
	|			ТОГДА &НепринятыйНовый
	|	КОНЕЦ,
	|	НепринятаяВерсия.ДатаВерсии,
	|	НепринятаяВерсия.ПредупреждениеСинхронизации,
	|	НЕОПРЕДЕЛЕНО,
	|	НепринятаяВерсия.ВерсияПроигнорирована,
	|	ВЫБОР
	|		КОГДА (ВЫРАЗИТЬ(НепринятаяВерсия.Комментарий КАК СТРОКА(1000))) = """"
	|			ТОГДА ЛОЖЬ
	|		ИНАЧЕ ИСТИНА
	|	КОНЕЦ,
	|	НепринятаяВерсия.Комментарий,
	|	ЕСТЬNULL(НепринятаяВерсия.НомерВерсии, 0),
	|	ЕСТЬNULL(ТекущаяВерсия.НомерВерсии, 0),
	|	НЕОПРЕДЕЛЕНО,
	|	ВЫБОР
	|		КОГДА
	|			НепринятаяВерсия.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе)
	|			ТОГДА ЛОЖЬ
	|		ИНАЧЕ ИСТИНА
	|	КОНЕЦ
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК НепринятаяВерсия
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВерсииОбъектов КАК ТекущаяВерсия
	|		ПО НепринятаяВерсия.Объект = ТекущаяВерсия.Объект
	|		И (НепринятаяВерсия.НомерВерсии = ТекущаяВерсия.НомерВерсии + 1)
	|ГДЕ
	|	НепринятаяВерсия.ТипВерсииОбъекта В
	|	(ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе),
	|		ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе))
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ВерсииДругойПрограммы.АвторВерсии,
	|	ВерсииДругойПрограммы.Объект,
	|	НЕОПРЕДЕЛЕНО,
	|	ВерсииДругойПрограммы.ТипВерсииОбъекта,
	|	ВЫБОР
	|		КОГДА ВерсииДругойПрограммы.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии)
	|			ТОГДА &ПринятыеДанныеКоллизии
	|		КОГДА ВерсииДругойПрограммы.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НеПринятыеДанныеПоКоллизии)
	|			ТОГДА &НепринятыеДанныеКоллизии
	|	КОНЕЦ,
	|	ВерсииДругойПрограммы.ДатаВерсии,
	|	ВерсииДругойПрограммы.ПредупреждениеСинхронизации,
	|	НЕОПРЕДЕЛЕНО,
	|	ВерсииДругойПрограммы.ВерсияПроигнорирована,
	|	ВЫБОР
	|		КОГДА (ВЫРАЗИТЬ(ВерсииДругойПрограммы.Комментарий КАК СТРОКА(1024))) = """"
	|			ТОГДА ЛОЖЬ
	|		ИНАЧЕ ИСТИНА
	|	КОНЕЦ,
	|	ВерсииДругойПрограммы.Комментарий,
	|	ЕСТЬNULL(ВерсииДругойПрограммы.НомерВерсии, 0),
	|	ЕСТЬNULL(ВерсииЭтойПрограммы.НомерВерсии, 0),
	|	ВЫБОР
	|		КОГДА ВерсииДругойПрограммы.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии)
	|			ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ,
	|	НЕОПРЕДЕЛЕНО
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииДругойПрограммы
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВерсииОбъектов КАК ВерсииЭтойПрограммы
	|		ПО ВерсииДругойПрограммы.Объект = ВерсииЭтойПрограммы.Объект
	|		И (ВерсииДругойПрограммы.НомерВерсии = ВерсииЭтойПрограммы.НомерВерсии + 1)
	|ГДЕ
	|	ВерсииДругойПрограммы.ТипВерсииОбъекта В (ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии),
	|		ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.НеПринятыеДанныеПоКоллизии))";
	
КонецФункции

// Возвращает описание команды для добавления в отчете "Результаты проверки учета".
// 
// Параметры:
//  Форма - ФормаКлиентскогоПриложения
// 
Функция КомандаИсторияИзменений(Форма) Экспорт
	
	Если Не ПолучитьФункциональнуюОпцию("ИспользоватьВерсионированиеОбъектов") Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Команда = Форма.Команды.Добавить("КонтрольВеденияУчетаИсторияИзмененийОбъекта");
	Команда.Действие  = "Подключаемый_Команда";
	Команда.Заголовок = НСтр("ru = 'История изменений объекта'");
	Команда.Подсказка = НСтр("ru = 'История изменений объекта'");
	Команда.Картинка  = БиблиотекаКартинок.ИсторияДанных;
	
	Возврат Команда;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.
Процедура ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаСсылок) Экспорт
	
	ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ВерсииОбъектов.ПолноеИмя());
	
КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтПодчиненного.
Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт
	
	Если ТипЗнч(ЭлементДанных) <> Тип("РегистрСведенийНаборЗаписей.ВерсииОбъектов") Или ЭлементДанных.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ПрочитатьИнформациюОбУзле(ЭлементДанных[0]);
	Объект = ЭлементДанных.Отбор.Объект.Значение;
	
	ПорядковыйНомерСинхронизируемойВерсии = ЭлементДанных.Отбор.НомерВерсии.Значение - ЭлементДанных[0].Смещение;
	ПорядковыйНомерВерсииВладельца = ЭлементДанных[0].ВерсияВладелец;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ВерсииОбъектов");
	ЭлементБлокировки.УстановитьЗначение("Объект", Объект);

	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		
		НомерВерсии = НомерВерсииВРегистре(Объект, ПорядковыйНомерСинхронизируемойВерсии);
		Если ЗначениеЗаполнено(ПорядковыйНомерВерсииВладельца) Тогда
			ЭлементДанных[0].ВерсияВладелец = НомерВерсииВРегистре(Объект, ПорядковыйНомерВерсииВладельца);
		КонецЕсли;
		
		НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.Объект.Установить(ЭлементДанных.Отбор.Объект.Значение);
		НаборЗаписей.Отбор.НомерВерсии.Установить(НомерВерсии);
		НаборЗаписей.Прочитать();
		
		Если ОбщегоНазначения.ЗначениеВСтрокуXML(ЭлементДанных) = ОбщегоНазначения.ЗначениеВСтрокуXML(НаборЗаписей) Тогда
			// Считаем, что нет коллизии.
			ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
			
			ЗафиксироватьТранзакцию();
			Возврат;
		КонецЕсли;
		
		ЕстьКоллизия = ПланыОбмена.ИзменениеЗарегистрировано(Отправитель.Ссылка, Объект);
		
		ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.НепринятыеДанныеПоКоллизии;
		Если Отправитель.ДополнительныеСвойства.Свойство("НепринятыеПоДатеЗапрета")
			И Отправитель.ДополнительныеСвойства.НепринятыеПоДатеЗапрета[Объект] <> Неопределено Тогда
				ЕстьКоллизия = Истина;
				Если Отправитель.ДополнительныеСвойства.НепринятыеПоДатеЗапрета[Объект] = "НепринятыйПоДатеЗапретаОбъектСуществуетВБазе" Тогда
					ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе;
				Иначе
					ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе;
				КонецЕсли;
		КонецЕсли;
		
		// Проверяем отмечена ли эта же версия к выгрузке.
		ВерсииКВыгрузке = ВерсииКВыгрузке(Объект, Отправитель.Ссылка);
		Для Каждого ВерсияКВыгрузке Из ВерсииКВыгрузке Цикл
			Если ВерсияКВыгрузке.НомерВерсии = НомерВерсии Тогда
				ЕстьКоллизия = Истина;
			КонецЕсли;
		КонецЦикла;
		
		Если Не ЕстьКоллизия Тогда
			ЗаписатьВерсиюСИзменениемНомера(ЭлементДанных, ПолучениеЭлемента, Отправитель, НомерВерсии);
			
			ЗафиксироватьТранзакцию();
			Возврат;
		КонецЕсли;
		
		Если ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.НепринятыеДанныеПоКоллизии Тогда
			ВерсииКВыгрузке = ВерсииКВыгрузке(Объект, Отправитель.Ссылка);
			Если ВерсииКВыгрузке.Количество() = 0 Тогда 
				ЗаписатьВерсиюСИзменениемНомера(ЭлементДанных, ПолучениеЭлемента, Отправитель, НомерВерсии);
				
				ЗафиксироватьТранзакцию();
				Возврат;
			КонецЕсли;
			
			МинимальныйНомерВерсии = ВерсииКВыгрузке[0].НомерВерсии;
			Для Счетчик = 1 По ВерсииКВыгрузке.Количество() - 1 Цикл
				Если ВерсииКВыгрузке[Счетчик - 1].НомерВерсии - ВерсииКВыгрузке[Счетчик].НомерВерсии = 1 Тогда
					МинимальныйНомерВерсии = Мин(МинимальныйНомерВерсии, ВерсииКВыгрузке[Счетчик].НомерВерсии);
				Иначе
					Прервать;
				КонецЕсли;
			КонецЦикла;
			
			Если МинимальныйНомерВерсии > НомерВерсии Тогда
				ЗаписатьВерсиюСИзменениемНомера(ЭлементДанных, ПолучениеЭлемента, Отправитель, НомерВерсии);
				
				ЗафиксироватьТранзакцию();
				Возврат;
			КонецЕсли;
		КонецЕсли;
			
		КоллизииВерсийОбъектов = Новый Соответствие;
		Если Отправитель.ДополнительныеСвойства.Свойство("КоллизииВерсийОбъектов") Тогда
			КоллизииВерсийОбъектов = Отправитель.ДополнительныеСвойства.КоллизииВерсийОбъектов;
		Иначе
			Отправитель.ДополнительныеСвойства.Вставить("КоллизииВерсийОбъектов", КоллизииВерсийОбъектов);
		КонецЕсли;
		
		НомерВерсииСКоллизией = КоллизииВерсийОбъектов[Объект];
		НомерПоследнейВерсии = НомерПоследнейВерсии(Объект);
		ОбновитьВерсиюСКоллизией = Истина;
		Если НомерВерсииСКоллизией = Неопределено Тогда
			НомерВерсииСКоллизией = НомерПоследнейВерсии + 1;
			
			НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
			НаборЗаписей.Отбор.Объект.Установить(Объект);
			НаборЗаписей.Отбор.НомерВерсии.Установить(НомерВерсииСКоллизией);
			Запись = НаборЗаписей.Добавить();
			ЗаполнитьЗначенияСвойств(Запись, ЭлементДанных[0]);
			Запись.НомерВерсии = НомерВерсииСКоллизией;
			Запись.ТипВерсииОбъекта = ТипВерсииОбъекта;
			Запись.ДатаВерсии = ТекущаяДатаСеанса();
			Запись.АвторВерсии = Отправитель.Ссылка;
			Запись.Узел = ОбщегоНазначения.ПредметСтрокой(Запись.АвторВерсии);
			Запись.ПредупреждениеСинхронизации = НСтр("ru = 'Отклоненная версия (автоматическое разрешение конфликта).'", ОбщегоНазначения.КодОсновногоЯзыка());
			НаборЗаписей.Записать();
			НомерПоследнейВерсии = НомерВерсииСКоллизией;
			КоллизииВерсийОбъектов.Вставить(Объект, НомерВерсииСКоллизией);
			ОбновитьВерсиюСКоллизией = Ложь;
		КонецЕсли;
		НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.Объект.Установить(Объект);
		НаборЗаписей.Отбор.НомерВерсии.Установить(НомерПоследнейВерсии + 1);
		Запись = НаборЗаписей.Добавить();
		ЗаполнитьЗначенияСвойств(Запись, ЭлементДанных[0]);
		Запись.НомерВерсии = НомерПоследнейВерсии + 1;
		Запись.ВерсияВладелец = НомерВерсииСКоллизией;
		Запись.ТипВерсииОбъекта = ТипВерсииОбъекта;
		НаборЗаписей.Записать();
		
		Если ОбновитьВерсиюСКоллизией Тогда
			НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
			НаборЗаписей.Отбор.Объект.Установить(Объект);
			НаборЗаписей.Отбор.НомерВерсии.Установить(НомерВерсииСКоллизией);
			НаборЗаписей.Прочитать();
			Для Каждого Запись Из НаборЗаписей Цикл
				Запись.КонтрольнаяСумма = ЭлементДанных[0].КонтрольнаяСумма;
				Запись.ВерсияОбъекта = ЭлементДанных[0].ВерсияОбъекта;
				Запись.РазмерДанных = ЭлементДанных[0].РазмерДанных;
				Запись.ЕстьДанныеВерсии = ЭлементДанных[0].ЕстьДанныеВерсии;
			КонецЦикла;
			НаборЗаписей.Записать();
		КонецЕсли;
		
		ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтГлавного.
Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт
	
	Если Отправитель = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(ЭлементДанных) <> Тип("РегистрСведенийНаборЗаписей.ВерсииОбъектов") Или ЭлементДанных.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ПрочитатьИнформациюОбУзле(ЭлементДанных[0]);
	Объект = ЭлементДанных.Отбор.Объект.Значение;
	
	// Сопоставляем входящие номера версии и владельца версии с номерами в этой ИБ.
	ПорядковыйНомерСинхронизируемойВерсии = ЭлементДанных.Отбор.НомерВерсии.Значение - ЭлементДанных[0].Смещение;
	ПорядковыйНомерВерсииВладельца = ЭлементДанных[0].ВерсияВладелец;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ВерсииОбъектов");
	ЭлементБлокировки.УстановитьЗначение("Объект", Объект);

	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		
		НомерВерсии = НомерВерсииВРегистре(Объект, ПорядковыйНомерСинхронизируемойВерсии);
		Если ЗначениеЗаполнено(ПорядковыйНомерВерсииВладельца) Тогда
			ЭлементДанных[0].ВерсияВладелец = НомерВерсииВРегистре(Объект, ПорядковыйНомерВерсииВладельца);
		КонецЕсли;
		
		// Сравниваем с имеющейся версией.
		НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.Объект.Установить(Объект);
		НаборЗаписей.Отбор.НомерВерсии.Установить(НомерВерсии);
		НаборЗаписей.Прочитать();
		
		Если ОбщегоНазначения.ЗначениеВСтрокуXML(ЭлементДанных) = ОбщегоНазначения.ЗначениеВСтрокуXML(НаборЗаписей) Тогда
			// Считаем, что нет коллизии.
			ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
			
			ЗафиксироватьТранзакцию();
			Возврат;
		КонецЕсли;
		
		ЕстьКоллизия = Объект.ПолучитьОбъект() <> Неопределено И ПланыОбмена.ИзменениеЗарегистрировано(Отправитель.Ссылка, Объект);
		
		ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.НепринятыеДанныеПоКоллизии;
		Если Отправитель.ДополнительныеСвойства.Свойство("НепринятыеПоДатеЗапрета")
			И Отправитель.ДополнительныеСвойства.НепринятыеПоДатеЗапрета[Объект] <> Неопределено Тогда
				ЕстьКоллизия = Истина;
				Если Отправитель.ДополнительныеСвойства.НепринятыеПоДатеЗапрета[Объект] = "НепринятыйПоДатеЗапретаОбъектСуществуетВБазе" Тогда
					ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектСуществуетВБазе;
				Иначе
					ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе;
				КонецЕсли;
		КонецЕсли;
		
		// Проверяем отмечена ли эта же версия к выгрузке.
		ВерсииКВыгрузке = ВерсииКВыгрузке(Объект, Отправитель.Ссылка);
		Для Каждого ВерсияКВыгрузке Из ВерсииКВыгрузке Цикл
			Если ВерсияКВыгрузке.НомерВерсии = НомерВерсии Тогда
				ЕстьКоллизия = Истина;
			КонецЕсли;
		КонецЦикла;
		
		// Записываем полученную версию, меняем ее номер с учетом несинхронизируемых версий.
		Если Не ЕстьКоллизия Тогда
			// Если объект не был изменен, то версия перезаписывается без проверки, так как неизвестно,
			// был ли изменен объект в узле-отправителе.
			Если НаборЗаписей.Количество() = 0 Тогда
				Запись = НаборЗаписей.Добавить();
				Запись.Объект = Объект;
				Запись.НомерВерсии = НомерВерсии;
			Иначе
				Запись = НаборЗаписей[0];
			КонецЕсли;
			ЗаполнитьЗначенияСвойств(Запись, ЭлементДанных[0], , "Объект,НомерВерсии");
			НаборЗаписей.Записать();
			ПланыОбмена.УдалитьРегистрациюИзменений(Отправитель.Ссылка, НаборЗаписей);
			ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
			
			ЗафиксироватьТранзакцию();
			Возврат;
		КонецЕсли;
		
		// Сохраняем данные последней записанной версии.
		НомерПоследнейВерсии = НомерПоследнейВерсии(Объект);
		ПоследняяВерсия = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
		ПоследняяВерсия.Объект = Объект;
		ПоследняяВерсия.НомерВерсии = НомерПоследнейВерсии;
		ПоследняяВерсия.Прочитать();
		Если Не ПоследняяВерсия.ЕстьДанныеВерсии Тогда
			ПоследняяВерсия.ВерсияОбъекта = Новый ХранилищеЗначения(ДанныеДляХранения(Объект), Новый СжатиеДанных(9));
			ПоследняяВерсия.Записать();
		КонецЕсли;
		
		Если ВерсииКВыгрузке.Количество() = 0 Тогда 
			ЗаписатьВерсиюСИзменениемНомера(ЭлементДанных, ПолучениеЭлемента, Отправитель, НомерВерсии);
			
			ЗафиксироватьТранзакцию();
			Возврат;
		КонецЕсли;
		
		// Сдвигаем все зарегистрированные к отправке версии для вставки версии из главного узла.
		
		Для Каждого ОписаниеВерсии Из ВерсииКВыгрузке Цикл
			Если ОписаниеВерсии.НомерВерсии >= НомерВерсии Тогда
				НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
				НаборЗаписей.Отбор.Объект.Установить(Объект);
				НаборЗаписей.Отбор.НомерВерсии.Установить(ОписаниеВерсии.НомерВерсии);
				НаборЗаписей.Прочитать();
				ПланыОбмена.УдалитьРегистрациюИзменений(Отправитель.Ссылка, НаборЗаписей);
			КонецЕсли;
		КонецЦикла;
		
		КоллизииВерсийОбъектов = Новый Соответствие;
		Если Отправитель.ДополнительныеСвойства.Свойство("КоллизииВерсийОбъектов") Тогда
			КоллизииВерсийОбъектов = Отправитель.ДополнительныеСвойства.КоллизииВерсийОбъектов;
		Иначе
			Отправитель.ДополнительныеСвойства.Вставить("КоллизииВерсийОбъектов", КоллизииВерсийОбъектов);
		КонецЕсли;
		
		// Запоминаем версию, которая будет использована в качестве владельца непринятых.
		НомерВерсииСКоллизией = КоллизииВерсийОбъектов[Объект];
		СдвигНомераВерсии = 1;
		УстановитьВладельцаНепринятыхВерсий = Ложь;
		Если НомерВерсииСКоллизией = Неопределено Тогда
			СдвигНомераВерсии = 2;
			НомерВерсииСКоллизией = НомерВерсии + 1;
			УстановитьВладельцаНепринятыхВерсий = Истина;
		КонецЕсли;
		
		НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.Объект.Установить(Объект);
		НаборЗаписей.Прочитать();
		
		ВерсииОбъекта = НаборЗаписей.Выгрузить();
		Для Каждого Версия Из ВерсииОбъекта Цикл
			НаборЗаписей.Отбор.НомерВерсии.Установить(Версия.НомерВерсии);
			НаборЗаписей.Прочитать();
			Запись = НаборЗаписей[0];
			Записать = Ложь;
			Если Запись.ВерсияВладелец >= НомерВерсии Тогда
				Запись.ВерсияВладелец = Запись.ВерсияВладелец + СдвигНомераВерсии;
				Записать = Истина;
			КонецЕсли;
			Если Запись.НомерВерсии >= НомерВерсии Тогда
				Запись.НомерВерсии = Запись.НомерВерсии + СдвигНомераВерсии;
				Запись.ТипВерсииОбъекта = ТипВерсииОбъекта;
				Если УстановитьВладельцаНепринятыхВерсий И Не ЗначениеЗаполнено(Запись.ВерсияВладелец) Тогда
					Запись.ВерсияВладелец = НомерВерсииСКоллизией;
				КонецЕсли;
				Записать = Истина;
			КонецЕсли;
			Если Записать Тогда
				Записи = НаборЗаписей.Выгрузить();
				НаборЗаписей.Очистить();
				НаборЗаписей.Записать();
				НаборЗаписей.Отбор.НомерВерсии.Установить(Записи[0].НомерВерсии);
				НаборЗаписей.Загрузить(Записи);
				НаборЗаписей.Записать();
			КонецЕсли;
		КонецЦикла;
		
		// Создаем версию-владельца непринятых версий.
		Если КоллизииВерсийОбъектов[Объект] = Неопределено Тогда
			НомерВерсииСКоллизией = НомерВерсии + 1;
			АвторВерсии = ОбщегоНазначения.МенеджерОбъектаПоСсылке(Отправитель.Ссылка).ЭтотУзел();
			НомерПоследнейОтклоненнойВерсии = ВерсииКВыгрузке[0].НомерВерсии + СдвигНомераВерсии;
			СоздатьВерсиюВладельцаНепринятых(НомерПоследнейОтклоненнойВерсии, НомерВерсииСКоллизией, Объект, АвторВерсии);
			КоллизииВерсийОбъектов.Вставить(Объект, НомерВерсииСКоллизией);
		КонецЕсли;
		
		ЗаписатьВерсиюСИзменениемНомера(ЭлементДанных, ПолучениеЭлемента, Отправитель, НомерВерсии);
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхПодчиненному.
Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Получатель) Экспорт
	
	ПриОтправкеДанныхПолучателю(ЭлементДанных, ОтправкаЭлемента, Получатель);
	
КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхГлавному.
Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Получатель) Экспорт
	
	ПриОтправкеДанныхПолучателю(ЭлементДанных, ОтправкаЭлемента, Получатель);
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса.
Процедура ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики) Экспорт
	
	Обработчики.Вставить("ВыполняетсяЗаписьОбъекта",
		"ВерсионированиеОбъектов.УстановкаПараметровСеанса");
	
КонецПроцедуры

// См. РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий
Процедура ПриОпределенииНастроекРегламентныхЗаданий(Настройки) Экспорт
	Настройка = Настройки.Добавить();
	Настройка.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ОчисткаУстаревшихВерсийОбъектов;
	Настройка.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ИспользоватьВерсионированиеОбъектов;
КонецПроцедуры

// Обработчик перехода на версию объекта.
//
// Параметры:
//  ОбъектСсылка - ЛюбаяСсылка - ссылка на объект, для которого имеется версия.
//  НомерВерсииДляПерехода - Число - номер версии, на которую необходимо выполнить переход.
//  НомерИгнорируемойВерсии - Число - номер версии, на которую необходимо проигнорировать.
//  ПропуститьПроверкуЗапретаИзменения - Булево - признак пропуска проверки даты запрета загрузки.
//
Процедура ПриПереходеНаВерсиюОбъекта(СсылкаНаОбъект, Знач НомерВерсии) Экспорт
	
	ОбъектМетаданных = СсылкаНаОбъект.Метаданные();
	ПроверитьНаличиеПравНаИзменениеОбъекта(ОбъектМетаданных);
	
	УстановитьПривилегированныйРежим(Истина);
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ВерсииОбъектов");
	ЭлементБлокировки.УстановитьЗначение("Объект", СсылкаНаОбъект);
	
	ЭлементБлокировки = Блокировка.Добавить(ОбъектМетаданных.ПолноеИмя());
	ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаОбъект);
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		ЗаблокироватьДанныеДляРедактирования(СсылкаНаОбъект);
		
		НаборЗаписей = ЗаписьОВерсииОбъекта(СсылкаНаОбъект, НомерВерсии);
		Запись = НаборЗаписей[0];
		
		Если Запись.ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии Тогда
			НомерВерсии = НомерВерсии - 1;
			Если НомерВерсии <> 0 Тогда
				ПредыдущаяЗапись = ЗаписьОВерсииОбъекта(СсылкаНаОбъект, НомерВерсии)[0];
				НомерВерсии = ПредыдущаяЗапись.НомерВерсии;
			КонецЕсли;
		Иначе
			НомерВерсии = Запись.НомерВерсии;
		КонецЕсли;
		
		ТекстСообщенияОбОшибке = "";
		ПерейтиНаВерсиюСервер(СсылкаНаОбъект, НомерВерсии, ТекстСообщенияОбОшибке);
		
		Если Не ПустаяСтрока(ТекстСообщенияОбОшибке) Тогда
			ВызватьИсключение ТекстСообщенияОбОшибке;
		КонецЕсли;
		
		Запись.ВерсияПроигнорирована = Истина;
		НаборЗаписей.Записать();
	
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Параметры:
//   ТекущиеДела - см. ТекущиеДелаСервер.ТекущиеДела.
//
Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт
	
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	Если Не ПолучитьФункциональнуюОпцию("ИспользоватьВерсионированиеОбъектов")
		Или Не ПравоДоступа("Редактирование", Метаданные.РегистрыСведений.НастройкиВерсионированияОбъектов)
		Или МодульТекущиеДелаСервер.ДелоОтключено("УстаревшиеВерсииОбъектов") Тогда
		Возврат;
	КонецЕсли;
	
	// Процедура вызывается только при наличии подсистемы "Текущие дела", поэтому здесь
	// не делается проверка существования подсистемы.
	Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта(Метаданные.РегистрыСведений.НастройкиВерсионированияОбъектов.ПолноеИмя());
	
	ИнформацияОбУстаревшихВерсиях = ИнформацияОбУстаревшихВерсиях();
	РазмерУстаревшихДанных = ИнформацияОбУстаревшихВерсиях.РазмерДанныхСтрокой;
	Подсказка = НСтр("ru = 'Устаревших версий: %1 (%2)'");
	
	Для Каждого Раздел Из Разделы Цикл
		ИдентификаторУстаревшиеОбъекты = "УстаревшиеВерсииОбъектов" + СтрЗаменить(Раздел.ПолноеИмя(), ".", "");
		// Добавление дела.
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор = ИдентификаторУстаревшиеОбъекты;
		// Выводим дело, если размер устаревших данных больше 1 Гб.
		Дело.ЕстьДела      = ИнформацияОбУстаревшихВерсиях.РазмерДанных > (1024 * 1024 * 1024);
		Дело.Представление = НСтр("ru = 'Устаревшие версии объектов'");
		Дело.Форма         = "РегистрСведений.НастройкиВерсионированияОбъектов.Форма.НастройкиХраненияИстории";
		Дело.Подсказка     = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Подсказка, ИнформацияОбУстаревшихВерсиях.КоличествоВерсий, РазмерУстаревшихДанных);
		Дело.Владелец      = Раздел;
	КонецЦикла;
	
КонецПроцедуры

// См. ОчередьЗаданийПереопределяемый.ПриОпределенииПсевдонимовОбработчиков.
Процедура ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам) Экспорт
	
	СоответствиеИменПсевдонимам.Вставить("ВерсионированиеОбъектов.ОчиститьУстаревшиеВерсииОбъектов");
	
КонецПроцедуры

// См. ЦентрМониторингаПереопределяемый.ПриСбореПоказателейСтатистикиКонфигурации.
Процедура ПриСбореПоказателейСтатистикиКонфигурации() Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЦентрМониторинга") Тогда
		Возврат;
	КонецЕсли;
	
	МодульЦентрМониторинга = ОбщегоНазначения.ОбщийМодуль("ЦентрМониторинга");
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ТИПЗНАЧЕНИЯ(ВерсииОбъектов.Объект) КАК ТипОбъекта,
	|	КОЛИЧЕСТВО(1) КАК Количество
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|
	|СГРУППИРОВАТЬ ПО
	|	ТИПЗНАЧЕНИЯ(ВерсииОбъектов.Объект)";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(Выборка.ТипОбъекта);
		Если ОбъектМетаданных <> Неопределено Тогда
			МодульЦентрМониторинга.ЗаписатьСтатистикуОбъектаКонфигурации("КоличествоВерсийОбъекта." + ОбъектМетаданных.ПолноеИмя(), Выборка.Количество);
		КонецЕсли;
	КонецЦикла;
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	НастройкиВерсионированияОбъектов.ТипОбъекта.ПолноеИмя КАК ИмяОбъекта
	|ИЗ
	|	РегистрСведений.НастройкиВерсионированияОбъектов КАК НастройкиВерсионированияОбъектов
	|ГДЕ
	|	НастройкиВерсионированияОбъектов.Использовать = ИСТИНА";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		МодульЦентрМониторинга.ЗаписатьСтатистикуОбъектаКонфигурации("ВключеноВерсионированиеОбъекта." + Выборка.ИмяОбъекта, Истина);
	КонецЦикла;
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных
Процедура ПриРегистрацииОбработчиковВыгрузкиДанных(ТаблицаОбработчиков) Экспорт
	
	Обработчик = ТаблицаОбработчиков.Добавить();
	Обработчик.ОбъектМетаданных = Метаданные.РегистрыСведений.ВерсииОбъектов;
	Обработчик.Обработчик = РегистрыСведений.ВерсииОбъектов;
	Обработчик.ПередВыгрузкойОбъекта = Истина;
	Обработчик.Версия = "1.0.0.1";
	
КонецПроцедуры

// см. УдалениеПомеченныхОбъектовПереопределяемый.ПередУдалениемГруппыОбъектов
Процедура ПередУдалениемГруппыОбъектов(Контекст, УдаляемыеОбъекты) Экспорт
	
	Контекст.Вставить("Версионирование_УдаляемыеОбъекты", УдаляемыеОбъекты);
	
КонецПроцедуры

// см. УдалениеПомеченныхОбъектовПереопределяемый.ПослеУдаленияГруппыОбъектов
Процедура ПослеУдаленияГруппыОбъектов(Контекст, Успешно) Экспорт
	
	Если Не Успешно Тогда
		Возврат;
	КонецЕсли;
	
	Для Каждого Ссылка Из Контекст.Версионирование_УдаляемыеОбъекты Цикл
		Если Метаданные.РегистрыСведений.ВерсииОбъектов.Реквизиты.АвторВерсии.Тип.СодержитТип(ТипЗнч(Ссылка)) Тогда
			РегистрыСведений.ВерсииОбъектов.УдалитьИнформациюОбАвтореВерсии(Ссылка);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Параметры:
//  ИмяПараметра - Строка
//  УстановленныеПараметры - Массив из Строка
//
Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт
	
	Если ИмяПараметра = "ВыполняетсяЗаписьОбъекта" Тогда
		ВыполняетсяЗаписьОбъекта(Ложь);
		УстановленныеПараметры.Добавить("ВыполняетсяЗаписьОбъекта");
	КонецЕсли;
	
КонецПроцедуры

// Создает и записывает версию объекта в информационную базу.
//
Процедура СоздатьВерсиюОбъекта(Объект, СведенияОВерсииОбъекта, ЗаписьОбычнойВерсии = Истина)
	
	ПроверитьНаличиеПравНаИзменениеОбъекта(Объект.Метаданные());
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если ЗаписьОбычнойВерсии Тогда
		ИзмененаПроведенность = Ложь;
		Если СведенияОВерсииОбъекта.Свойство("ИзмененаПроведенность") Тогда
			ИзмененаПроведенность = СведенияОВерсииОбъекта.ИзмененаПроведенность;
		КонецЕсли;
		
		// Запись данных предыдущей версии.
		Если Не Объект.ЭтоНовый() И (ИзмененаПроведенность И СведенияОВерсииОбъекта.НомерВерсии > 1 Или ВерсияОтличаетсяОтРанееЗаписанной(Объект)) Тогда
			// Если версионирование включено после создания объекта, создаем предыдущую запись о версии.
			Если СведенияОВерсииОбъекта.НомерВерсии = 1 Тогда
				Если ОбъектВерсионируется(Объект.Ссылка) Тогда
					ПараметрыВерсии = Новый Структура;
					ПараметрыВерсии.Вставить("НомерВерсии", 1);
					ПараметрыВерсии.Вставить("Комментарий", НСтр("ru = 'Версия создана по уже имеющемуся объекту'"));
					СоздатьВерсиюОбъекта(Объект.Ссылка.ПолучитьОбъект(), ПараметрыВерсии);
					СведенияОВерсииОбъекта.НомерВерсии = 2;
				КонецЕсли;
			КонецЕсли;
			
			// Сохраняем предыдущую версию объекта.
			МенеджерЗаписи = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
			МенеджерЗаписи.Объект = Объект.Ссылка;
			МенеджерЗаписи.НомерВерсии = НомерПредыдущейВерсии(Объект.Ссылка, СведенияОВерсииОбъекта.НомерВерсии);
			МенеджерЗаписи.Прочитать();
			Если МенеджерЗаписи.Выбран() И Не МенеджерЗаписи.ЕстьДанныеВерсии Тогда
				МенеджерЗаписи.ВерсияОбъекта = Новый ХранилищеЗначения(ДанныеДляХранения(Объект.Ссылка), Новый СжатиеДанных(9));
				МенеджерЗаписи.Записать();
			КонецЕсли;
		КонецЕсли;
		
		СсылкаНаОбъект = Объект.Ссылка;
		Если СсылкаНаОбъект.Пустая() Тогда
			СсылкаНаОбъект = Объект.ПолучитьСсылкуНового();
			Если СсылкаНаОбъект.Пустая() Тогда
				СсылкаНаОбъект = ОбщегоНазначения.МенеджерОбъектаПоСсылке(Объект.Ссылка).ПолучитьСсылку();
				Объект.УстановитьСсылкуНового(СсылкаНаОбъект);
			КонецЕсли;
		КонецЕсли;
		
		// Запись текущей версии без данных.
		МенеджерЗаписи = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.Объект = СсылкаНаОбъект;
		МенеджерЗаписи.НомерВерсии = СведенияОВерсииОбъекта.НомерВерсии;
		МенеджерЗаписи.ДатаВерсии = ТекущаяДатаСеанса();
		
		АвторВерсии = Неопределено;
		Если Не Объект.ДополнительныеСвойства.Свойство("АвторВерсии", АвторВерсии) Тогда
			АвторВерсии = Пользователи.АвторизованныйПользователь();
		КонецЕсли;
		МенеджерЗаписи.АвторВерсии = АвторВерсии;
		
		МенеджерЗаписи.ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.ИзмененоПользователем;
		МенеджерЗаписи.Синхронизируется = Истина;
		СведенияОВерсииОбъекта.Свойство("Комментарий", МенеджерЗаписи.Комментарий);
		СведенияОВерсииОбъекта.Свойство("ПредупреждениеСинхронизации", МенеджерЗаписи.ПредупреждениеСинхронизации);
		
		Если Не Объект.ЭтоНовый() Тогда
			// Перед тем как посчитать контрольную сумму, необходимо установить проведенность в состояние,
			// которое ожидается после записи документа.
			Если ИзмененаПроведенность Тогда
				Объект.Проведен = Не Объект.Проведен;
			КонецЕсли;
			
			МенеджерЗаписи.КонтрольнаяСумма = КонтрольнаяСумма(ДанныеДляХранения(Объект));
			
			// Возвращаем проведенность в исходное состояние, чтобы не поломать другие механизмы, зависящие от этого реквизита.
			Если ИзмененаПроведенность Тогда
				Объект.Проведен = Не Объект.Проведен;
			КонецЕсли;
		КонецЕсли;
	Иначе
		// Сохраняем предыдущую версию объекта.
		МенеджерЗаписи = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.Объект = Объект.Ссылка;
		МенеджерЗаписи.НомерВерсии = НомерПредыдущейВерсии(Объект.Ссылка, СведенияОВерсииОбъекта.НомерВерсии);
		МенеджерЗаписи.Прочитать();
		Если МенеджерЗаписи.Выбран() И Не МенеджерЗаписи.ЕстьДанныеВерсии Тогда
			МенеджерЗаписи.ВерсияОбъекта = Новый ХранилищеЗначения(ДанныеДляХранения(Объект.Ссылка), Новый СжатиеДанных(9));
			МенеджерЗаписи.Записать();
		КонецЕсли;
		
		ХранилищеДанных = Новый ХранилищеЗначения(ДанныеДляХранения(Объект), Новый СжатиеДанных(9));
		МенеджерЗаписи = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.ДатаВерсии = ТекущаяДатаСеанса();
		МенеджерЗаписи.ВерсияОбъекта = ХранилищеДанных;
		ЗаполнитьЗначенияСвойств(МенеджерЗаписи, СведенияОВерсииОбъекта);
	КонецЕсли;
	
	МенеджерЗаписи.Записать();
	
КонецПроцедуры

// Записывает версию объекта в информационную базу.
//
// Параметры:
//  Объект - для создания версии.
//
Процедура ПриСозданииВерсииОбъекта(Объект, РежимЗаписи)
	
	Перем Комментарий;
	
	Если НЕ ОбъектВерсионируется(Объект, РежимЗаписи = РежимЗаписиДокумента.Проведение
		Или РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения) Тогда
			Возврат;
	КонецЕсли;
	НомерПоследнейВерсии = НомерПоследнейВерсии(Объект.Ссылка);
	
	Если НЕ Объект.ДополнительныеСвойства.Свойство("ВерсионированиеОбъектовКомментарийКВерсии", Комментарий) Тогда
		Комментарий = "";
	КонецЕсли;
	
	СведенияОВерсииОбъекта = Новый Структура;
	СведенияОВерсииОбъекта.Вставить("НомерВерсии", Число(НомерПоследнейВерсии) + 1);
	СведенияОВерсииОбъекта.Вставить("Комментарий", Комментарий);
	
	ИзмененаПроведенность = (РежимЗаписи = РежимЗаписиДокумента.Проведение И Не Объект.Проведен
		Или РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения И Объект.Проведен);
	СведенияОВерсииОбъекта.Вставить("ИзмененаПроведенность", ИзмененаПроведенность);
	
	СоздатьВерсиюОбъекта(Объект, СведенияОВерсииОбъекта);
	
КонецПроцедуры

Процедура ЗаписатьДанныеТекущейВерсии(Ссылка, ОбменДаннымиЗагрузка = Ложь)
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если Не ОбъектВерсионируется(Ссылка) Тогда
		Возврат;
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ВерсииОбъектов");
	ЭлементБлокировки.УстановитьЗначение("Объект", Ссылка);
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
	
		НомерПоследнейВерсии = НомерПоследнейВерсии(Ссылка);
		
		ВерсияОбъекта = Новый ХранилищеЗначения(ДанныеДляХранения(Ссылка), Новый СжатиеДанных(9));
		
		НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.Объект.Установить(Ссылка);
		НаборЗаписей.Отбор.НомерВерсии.Установить(НомерПоследнейВерсии);
		НаборЗаписей.Прочитать();
		
		Для Каждого Запись Из НаборЗаписей Цикл
			Если Запись.ВерсияОбъекта.Получить() = Неопределено Тогда
				Запись.ВерсияОбъекта = ВерсияОбъекта;
			КонецЕсли;
		КонецЦикла;
		
		Если ОбменДаннымиЗагрузка Тогда
			НаборЗаписей.ДополнительныеСвойства.Вставить("РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ", Ложь);
		КонецЕсли;
		НаборЗаписей.Записать();
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры


Функция ЗаписьОВерсииОбъекта(СсылкаНаОбъект, НомерВерсии)
	
	НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект);
	НаборЗаписей.Отбор.НомерВерсии.Установить(НомерВерсии);
	НаборЗаписей.Прочитать();
	
	Возврат НаборЗаписей;
	
КонецФункции

Процедура ПроверитьНаличиеПравНаИзменениеОбъекта(ОбъектМетаданных)
	
	Если Не ПривилегированныйРежим() И Не ПравоДоступа("Изменение", ОбъектМетаданных)Тогда
		ТекстСообщения = НСтр("ru = 'Недостаточно прав на изменение ""%1"".'");
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения, ОбъектМетаданных.Представление());
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;
	
КонецПроцедуры

// Возвращает табличный документ, заполненный данными объекта.
// 
// Параметры:
//  СсылкаНаОбъект - ЛюбаяСсылка.
//
// Возвращаемое значение:
//  ТабличныйДокумент - печатная форма объекта.
//
Функция ОтчетПоВерсииОбъекта(СсылкаНаОбъект, Знач ВерсияОбъекта = Неопределено, ПользовательскийНомерВерсии = Неопределено) Экспорт
	
	НомерВерсии = Неопределено;
	СериализованныйОбъект = Неопределено;
	Если ТипЗнч(ВерсияОбъекта) = Тип("Число") Тогда
		НомерВерсии = ВерсияОбъекта;
	ИначеЕсли ТипЗнч(ВерсияОбъекта) = Тип("Строка") Тогда
		СериализованныйОбъект = ВерсияОбъекта;
	КонецЕсли;
	
	Если НомерВерсии = Неопределено Тогда
		Если СериализованныйОбъект = Неопределено Тогда
			СериализованныйОбъект = СериализоватьОбъект(СсылкаНаОбъект.ПолучитьОбъект());
		КонецЕсли;
		ОписаниеОбъекта = РазборПредставленияОбъектаXML(СериализованныйОбъект, СсылкаНаОбъект);
		ОписаниеОбъекта.Вставить("ИмяОбъекта",     Строка(СсылкаНаОбъект));
		ОписаниеОбъекта.Вставить("АвторИзменения", "");
		ОписаниеОбъекта.Вставить("ДатаИзменения",  ТекущаяДатаСеанса());
		ОписаниеОбъекта.Вставить("Комментарий", "");
		НомерВерсии = 0;
		
		ВерсионированиеОбъектовПереопределяемый.ПослеРазбораВерсииОбъекта(СсылкаНаОбъект, ОписаниеОбъекта);
	Иначе
		ОписаниеОбъекта = РазборВерсии(СсылкаНаОбъект, НомерВерсии);
	КонецЕсли;
	
	Если ПользовательскийНомерВерсии = Неопределено Тогда
		ПользовательскийНомерВерсии = НомерВерсииВИерархии(СсылкаНаОбъект, НомерВерсии);
	КонецЕсли;
	
	Описание = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '№ %1 / (%2) / %3'"), ПользовательскийНомерВерсии,
		Строка(ОписаниеОбъекта.ДатаИзменения), СокрЛП(Строка(ОписаниеОбъекта.АвторИзменения)));
		
	ОписаниеОбъекта.Вставить("Описание", Описание);
	ОписаниеОбъекта.Вставить("НомерВерсии", НомерВерсии);
	Возврат СформироватьОтчетПоВерсииОбъекта(ОписаниеОбъекта, СсылкаНаОбъект);
	
КонецФункции

// Возвращает номер последней записанной версии объекта.
//
// Параметры:
//  Ссылка - ЛюбаяСсылка - ссылка на объект информационной базы.
//
// Возвращаемое значение:
//  Число - номер версии объекта.
//
Функция НомерПоследнейВерсии(Ссылка, ИзмененныеПользователем = Ложь) Экспорт
	
	Если Ссылка.Пустая() Тогда
		Возврат 0;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ЕСТЬNULL(МАКСИМУМ(ВерсииОбъектов.НомерВерсии), 0) КАК НомерВерсии
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.Объект = &Ссылка
	|	И &ДополнительноеУсловие";
	
	Если ИзмененныеПользователем Тогда
		ДополнительноеУсловие = "ВерсииОбъектов.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.ИзмененоПользователем)";
	Иначе
		ДополнительноеУсловие = "ИСТИНА";
	КонецЕсли;
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДополнительноеУсловие", ДополнительноеУсловие);
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	Запрос.УстановитьПараметр("ИзмененныеПользователем", ИзмененныеПользователем);
	
	Если ТранзакцияАктивна() Тогда
		БлокировкаДанных = Новый БлокировкаДанных();
		ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрСведений.ВерсииОбъектов");
		ЭлементБлокировки.УстановитьЗначение("Объект", Ссылка);
		БлокировкаДанных.Заблокировать();
	КонецЕсли;
	
	Выборка = Запрос.Выполнить().Выбрать();
	Выборка.Следующий();
	
	Возврат Выборка.НомерВерсии;
	
КонецФункции

// Номер предыдущей версии, измененной пользователем.
Функция НомерПредыдущейВерсии(Ссылка, ТекущийНомерВерсии)
	
	Если Ссылка.Пустая() Тогда
		Возврат 0;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ЕСТЬNULL(МАКСИМУМ(ВерсииОбъектов.НомерВерсии), -1) КАК НомерВерсии
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.Объект = &Ссылка
	|	И ВерсииОбъектов.ТипВерсииОбъекта = ЗНАЧЕНИЕ(Перечисление.ТипыВерсийОбъекта.ИзмененоПользователем)
	|	И ВерсииОбъектов.НомерВерсии < &ТекущийНомерВерсии";
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	Запрос.УстановитьПараметр("ТекущийНомерВерсии", ТекущийНомерВерсии);
	
	Выборка = Запрос.Выполнить().Выбрать();
	Выборка.Следующий();
	
	Возврат Выборка.НомерВерсии;
	
КонецФункции

// Возвращает вариант версионирования для указанного объекта метаданных.
//
// Параметры:
//  ТипОбъекта - СправочникСсылка.ИдентификаторыОбъектовМетаданных - объект.
//
// Возвращаемое значение:
//  ПеречислениеСсылка.ВариантыВерсионированияОбъектов.
//
Функция ВариантВерсионированияОбъекта(ТипОбъекта)
	
	Возврат ПолучитьФункциональнуюОпцию("ВариантыВерсионированияОбъектов",
		Новый Структура("ТипВерсионируемогоОбъекта", ТипОбъекта));
		
КонецФункции	

// Получает объект по его сериализованному XML представлению.
//
// Параметры:
//  АдресВоВременномХранилище - Строка - адрес двоичных данных во временном хранилище.
//  ТекстСообщенияОбОшибке    - Строка - текст ошибки (возвращаемый параметр), если восстановить объект не удалось.
//
// Возвращаемое значение:
//  Произвольный - объект или Неопределено, если не удалось восстановить объект.
//
Функция ВосстановитьОбъектПоXML(ДанныеОбъекта, ТекстСообщенияОбОшибке = "")
	
	УстановитьПривилегированныйРежим(Истина);
	
	ДвоичныеДанные = ДанныеОбъекта;
	Если ТипЗнч(ДанныеОбъекта) = Тип("Структура") Тогда
		ДвоичныеДанные = ДанныеОбъекта.Объект;
	КонецЕсли;
	
	ЧтениеFastInfoSet = Новый ЧтениеFastInfoSet;
	ЧтениеFastInfoSet.УстановитьДвоичныеДанные(ДвоичныеДанные);
	
	Попытка
		Объект = ПрочитатьXML(ЧтениеFastInfoSet);
	Исключение
		ЗаписьЖурналаРегистрации(НСтр("ru = 'Версионирование'", ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ТекстСообщенияОбОшибке = НСтр("ru = 'Не удалось перейти на выбранную версию.
											|Возможная причина: версия объекта была записана в другой версии программы.
											|Техническая информация об ошибке: %1'");
		ТекстСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщенияОбОшибке, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат Неопределено;
	КонецПопытки;
	
	Возврат Объект;
	
КонецФункции

// Возвращает структуру, содержащую версию объекта и дополнительную информацию.
//
// Параметры:
//  Ссылка      - ЛюбаяСсылка - версионируемый объект;
//  НомерВерсии - Число  - номер версии объекта.
//
// Возвращаемое значение:
//   Структура:
//                          ВерсияОбъекта - ДвоичныеДанные - сохраненная версия объекта информационной базы;
//                          АвторВерсии   - СправочникСсылка.Пользователи
//                                        - СправочникСсылка.ВнешниеПользователи -
//                                          пользователь, записавший версию объекта.
//                          ДатаВерсии    - Дата - дата записи версии объекта.
// 
// Примечание:
//  Функция может вызвать исключение, если запись не содержит данных.
//  Функцию требуется вызвать в привилегированном режиме.
//
Функция СведенияОВерсииОбъекта(Знач Ссылка, Знач НомерВерсии) Экспорт
	СообщениеНеУдалосьПолучитьВерсию = НСтр("ru = 'Не удалось получить предыдущую версию объекта.'");
	Если Не ЕстьПравоЧтенияДанныхВерсийОбъектов() Тогда
		ВызватьИсключение СообщениеНеУдалосьПолучитьВерсию;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ВерсииОбъектов.АвторВерсии КАК АвторВерсии,
	|	ВерсииОбъектов.ДатаВерсии КАК ДатаВерсии,
	|	ВерсииОбъектов.Комментарий КАК Комментарий,
	|	ВерсииОбъектов.ПредупреждениеСинхронизации КАК ПредупреждениеСинхронизации,
	|	ВерсииОбъектов.ВерсияОбъекта КАК ВерсияОбъекта,
	|	ВерсииОбъектов.КонтрольнаяСумма КАК КонтрольнаяСумма
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.Объект = &Ссылка
	|	И ВерсииОбъектов.НомерВерсии = &НомерВерсии";
	
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	Запрос.УстановитьПараметр("НомерВерсии", Число(НомерВерсии));
	
	Результат = Новый Структура("ВерсияОбъекта, АвторВерсии, ДатаВерсии, Комментарий, ПредупреждениеСинхронизации");
	
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		
		ЗаполнитьЗначенияСвойств(Результат, Выборка);
		
		Результат.ВерсияОбъекта = Результат.ВерсияОбъекта.Получить();
		Если Результат.ВерсияОбъекта = Неопределено Тогда
			Результат.ВерсияОбъекта = ДанныеВерсииОбъекта(Ссылка, НомерВерсии, Выборка.КонтрольнаяСумма);
		КонецЕсли;
		
	КонецЕсли;
	
	Если Результат.ВерсияОбъекта = Неопределено Тогда
		ВызватьИсключение НСтр("ru = 'Выбранная версия объекта отсутствует в программе.'");
	КонецЕсли;
	
	Возврат Результат;
		
КонецФункции

// Проверяет настройки версионирования по переданному объекту и
// и возвращает вариант версионирования. Если по объекту не настроено
// версионирование, то он версионируется в соответствии с правилами
// версионирования "по умолчанию".
//
Функция ОбъектВерсионируется(Знач Источник, РежимЗаписиПроведение = Ложь)
	
	// Проверяем, что подсистема версионирования включена.
	Если НЕ ПолучитьФункциональнуюОпцию("ИспользоватьВерсионированиеОбъектов") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ВариантВерсионирования = ВариантВерсионированияОбъекта(ОбщегоНазначения.ИдентификаторОбъектаМетаданных(Источник.Метаданные()));
	Если ВариантВерсионирования = Ложь Тогда
		ВариантВерсионирования = Перечисления.ВариантыВерсионированияОбъектов.НеВерсионировать;
	КонецЕсли;
	
	Возврат ВариантВерсионирования = Перечисления.ВариантыВерсионированияОбъектов.ВерсионироватьПриЗаписи
		Или ВариантВерсионирования = Перечисления.ВариантыВерсионированияОбъектов.ВерсионироватьПриПроведении И (РежимЗаписиПроведение Или Источник.Проведен)
		Или ВариантВерсионирования = Перечисления.ВариантыВерсионированияОбъектов.ВерсионироватьПриСтарте И Источник.Стартован;
	
КонецФункции

// Контрольная сумма по алгоритму MD5.
Функция КонтрольнаяСумма(Данные) Экспорт
	ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.MD5);
	
	Если ТипЗнч(Данные) = Тип("Структура") Тогда
		ХешированиеДанных.Добавить(Данные.Объект);
		Если Данные.Свойство("ДополнительныеРеквизиты") Тогда
			ХешированиеДанных.Добавить(ОбщегоНазначения.ЗначениеВСтрокуXML(Данные.ДополнительныеРеквизиты));
		КонецЕсли;
	Иначе
		ХешированиеДанных.Добавить(Данные);
	КонецЕсли;
	
	Возврат СтрЗаменить(ХешированиеДанных.ХешСумма, " ", "");
КонецФункции

Функция ДанныеВерсииОбъекта(СсылкаНаОбъект, НомерВерсии, КонтрольнаяСумма)
	
	Если Не ПустаяСтрока(КонтрольнаяСумма) Тогда
		ТекстЗапроса = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ВерсииОбъектов.ВерсияОбъекта,
		|	ВерсииОбъектов.НомерВерсии
		|ИЗ
		|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
		|ГДЕ
		|	ВерсииОбъектов.Объект = &Объект
		|	И ВерсииОбъектов.НомерВерсии >= &НомерВерсии
		|	И ВерсииОбъектов.КонтрольнаяСумма = &КонтрольнаяСумма
		|
		|УПОРЯДОЧИТЬ ПО
		|	ВерсииОбъектов.НомерВерсии УБЫВ";
		
		Запрос = Новый Запрос(ТекстЗапроса);
		Запрос.УстановитьПараметр("Объект", СсылкаНаОбъект);
		Запрос.УстановитьПараметр("НомерВерсии", НомерВерсии);
		Запрос.УстановитьПараметр("КонтрольнаяСумма", КонтрольнаяСумма);
		
		Выборка = Запрос.Выполнить().Выбрать();
		Если Выборка.Следующий() Тогда
			Результат = Выборка.ВерсияОбъекта.Получить();
			Если Результат = Неопределено И Выборка.НомерВерсии = НомерПоследнейВерсии(СсылкаНаОбъект, Истина) Тогда
				Результат = ДанныеДляХранения(СсылкаНаОбъект);
			КонецЕсли;
			Возврат Результат;
		КонецЕсли;
	Иначе
		ТекстЗапроса = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ВерсииОбъектов.КонтрольнаяСумма
		|ИЗ
		|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
		|ГДЕ
		|	ВерсииОбъектов.Объект = &Объект
		|	И ВерсииОбъектов.НомерВерсии >= &НомерВерсии
		|	И ВерсииОбъектов.КонтрольнаяСумма <> """"
		|
		|УПОРЯДОЧИТЬ ПО
		|	ВерсииОбъектов.НомерВерсии";
		
		Запрос = Новый Запрос(ТекстЗапроса);
		Запрос.УстановитьПараметр("Объект", СсылкаНаОбъект);
		Запрос.УстановитьПараметр("НомерВерсии", НомерВерсии);
		
		Выборка = Запрос.Выполнить().Выбрать();
		Если Выборка.Следующий() Тогда
			Возврат ДанныеВерсииОбъекта(СсылкаНаОбъект, НомерВерсии, Выборка.КонтрольнаяСумма);
		КонецЕсли;
		
		Возврат ДанныеДляХранения(СсылкаНаОбъект);
	КонецЕсли;
	
КонецФункции

Функция ВерсияОтличаетсяОтРанееЗаписанной(Объект)
	
	ТекстЗапроса = 
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	ВерсииОбъектов.КонтрольнаяСумма
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.Объект = &Объект
	|
	|УПОРЯДОЧИТЬ ПО
	|	ВерсииОбъектов.НомерВерсии УБЫВ";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Объект", Объект.Ссылка);
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() И Не ПустаяСтрока(Выборка.КонтрольнаяСумма) Тогда
		Возврат Выборка.КонтрольнаяСумма <> КонтрольнаяСумма(ДанныеДляХранения(Объект));
	КонецЕсли;
	
	Возврат Объект.ЭтоНовый() Или КонтрольнаяСумма(ДанныеДляХранения(Объект)) <> КонтрольнаяСумма(ДанныеДляХранения(Объект.Ссылка.ПолучитьОбъект()));
	
КонецФункции

// Только для служебного использования.
Процедура ОчиститьУстаревшиеВерсииОбъектов() Экспорт
	
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.ОчисткаУстаревшихВерсийОбъектов);
	
	УстановитьПривилегированныйРежим(Истина);
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ВерсииОбъектов.Объект,
	|	ВерсииОбъектов.НомерВерсии
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.ЕстьДанныеВерсии
	|	И &ДополнительныеУсловия";
	
	Запрос = ЗапросПоУстаревшимВерсиям(ТекстЗапроса);
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		МенеджерЗаписи = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.Объект = Выборка.Объект;
		МенеджерЗаписи.НомерВерсии = Выборка.НомерВерсии;
		МенеджерЗаписи.Прочитать();
		МенеджерЗаписи.ВерсияОбъекта = Неопределено;
		МенеджерЗаписи.Записать();
	КонецЦикла;
	
КонецПроцедуры

Функция ГраницыУдаленияОбъектов()
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("СписокТипов", Новый ОписаниеТипов("Массив"));
	Результат.Колонки.Добавить("ГраницаУдаления", Новый ОписаниеТипов("Дата"));
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ИдентификаторыОбъектовМетаданных.ПолноеИмя КАК ТипОбъекта,
	|	НастройкиВерсионированияОбъектов.СрокХраненияВерсий КАК СрокХраненияВерсий
	|ИЗ
	|	РегистрСведений.НастройкиВерсионированияОбъектов КАК НастройкиВерсионированияОбъектов
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ИдентификаторыОбъектовМетаданных
	|		ПО НастройкиВерсионированияОбъектов.ТипОбъекта = ИдентификаторыОбъектовМетаданных.Ссылка
	|ГДЕ
	|	НЕ ИдентификаторыОбъектовМетаданных.ПометкаУдаления
	|	И ИдентификаторыОбъектовМетаданных.ЗначениеПустойСсылки <> НЕОПРЕДЕЛЕНО
	|
	|УПОРЯДОЧИТЬ ПО
	|	СрокХраненияВерсий
	|ИТОГИ ПО
	|	СрокХраненияВерсий";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	ВыборкаСроковХранения = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	Пока ВыборкаСроковХранения.Следующий() Цикл
		ВыборкаОбъектов = ВыборкаСроковХранения.Выбрать();
		СписокТипов = Новый Массив;
		Пока ВыборкаОбъектов.Следующий() Цикл
			СписокТипов.Добавить(ВыборкаОбъектов.ТипОбъекта);
		КонецЦикла;
		СоответствиеГраницыТипамОбъектов = Результат.Добавить();
		СоответствиеГраницыТипамОбъектов.ГраницаУдаления = ГраницаУдаления(ВыборкаСроковХранения.СрокХраненияВерсий);
		СоответствиеГраницыТипамОбъектов.СписокТипов = СписокТипов;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ГраницаУдаления(СрокХраненияВерсий)
	Если СрокХраненияВерсий = Перечисления.СрокиХраненияВерсий.ЗаПоследнийГод Тогда
		Возврат ДобавитьМесяц(ТекущаяДатаСеанса(), -12);
	ИначеЕсли СрокХраненияВерсий = Перечисления.СрокиХраненияВерсий.ЗаПоследниеШестьМесяцев Тогда
		Возврат ДобавитьМесяц(ТекущаяДатаСеанса(), -6);
	ИначеЕсли СрокХраненияВерсий = Перечисления.СрокиХраненияВерсий.ЗаПоследниеТриМесяца Тогда
		Возврат ДобавитьМесяц(ТекущаяДатаСеанса(), -3);
	ИначеЕсли СрокХраненияВерсий = Перечисления.СрокиХраненияВерсий.ЗаПоследнийМесяц Тогда
		Возврат ДобавитьМесяц(ТекущаяДатаСеанса(), -1);
	ИначеЕсли СрокХраненияВерсий = Перечисления.СрокиХраненияВерсий.ЗаПоследнююНеделю Тогда
		Возврат ТекущаяДатаСеанса() - 7*24*60*60;
	Иначе // СрокХраненияВерсий = Перечисления.СрокиХраненияВерсий.Бессрочно
		Возврат '000101010000';
	КонецЕсли;
КонецФункции

// Параметры:
//   ЭлементДанных
//   ОтправкаЭлемента - ОтправкаЭлементаДанных
//   Получатель - ПланОбменаОбъект
//
Процедура ПриОтправкеДанныхПолучателю(ЭлементДанных, ОтправкаЭлемента, Получатель)
	
	Если ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ВерсииОбъектов") И ЭлементДанных.Количество() > 0 Тогда
		Запись = ЭлементДанных[0];
		
		Если Не Запись.Синхронизируется Или Запись.Объект = Неопределено Тогда
			ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
			Возврат;
		КонецЕсли;
		
		Объект = Запись.Объект.ПолучитьОбъект();
		Если Объект = Неопределено Тогда
			ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
			Возврат;
		КонецЕсли;
		
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
			ИмяПланаОбмена = Получатель.Метаданные().Имя;
			
			МодульОбменДаннымиСлужебный = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСлужебный");
			ОписаниеОбъектаМетаданных = МодульОбменДаннымиСлужебный.СоставПланаОбмена(ИмяПланаОбмена).Найти(ТипЗнч(Запись.Объект), "Тип");
			
			Если ОписаниеОбъектаМетаданных = Неопределено Тогда
				ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
				Возврат;
			КонецЕсли;
			
			Отказ = Ложь;
			
			МодульОбменДаннымиСобытия = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСобытия");
			МодульОбменДаннымиСобытия.МеханизмРегистрацииОбъектовПередЗаписью(ИмяПланаОбмена, Объект, Отказ);
			
			Если Отказ Или Не Объект.ОбменДанными.Получатели.Содержит(Получатель.Ссылка) Тогда
				ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
				Возврат;
			КонецЕсли;
		КонецЕсли;
		
		ДобавитьИнформациюОбУзле(Запись, Получатель);
		
		Если НомерПоследнейВерсии(Запись.Объект, Истина) = Запись.НомерВерсии Тогда
			Запись.ВерсияОбъекта = Новый ХранилищеЗначения(ДанныеДляХранения(Запись.Объект), Новый СжатиеДанных(9));
			Запись.РазмерДанных = РазмерДанных(Запись.ВерсияОбъекта);
			Запись.ЕстьДанныеВерсии = Истина;
		КонецЕсли;
		
		Запись.Смещение = КоличествоНесинхронизируемыхВерсий(Запись.Объект, Запись.НомерВерсии);
		Если ЗначениеЗаполнено(Запись.ВерсияВладелец) Тогда
			Запись.ВерсияВладелец = Запись.ВерсияВладелец - КоличествоНесинхронизируемыхВерсий(Запись.Объект, Запись.ВерсияВладелец);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Только для служебного использования.
// Комментарий записывается, если пользователь является либо автором версии, либо администратором.
//
Процедура ДобавитьКомментарийКВерсии(СсылкаНаОбъект, НомерВерсии, Комментарий) Экспорт
	
	Если Не ЕстьПравоЧтенияДанныхВерсийОбъектов() Тогда
		Возврат;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	МенеджерЗаписи = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
	МенеджерЗаписи.Объект = СсылкаНаОбъект;
	МенеджерЗаписи.НомерВерсии = НомерВерсии;
	МенеджерЗаписи.Прочитать();
	Если МенеджерЗаписи.Выбран() Тогда
		Если МенеджерЗаписи.АвторВерсии = Пользователи.ТекущийПользователь() Или Пользователи.ЭтоПолноправныйПользователь(, , Ложь) Тогда
			МенеджерЗаписи.Комментарий = Комментарий;
			МенеджерЗаписи.Записать();
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Предоставляет информацию о количестве и объеме устаревших версий объектов.
Функция ИнформацияОбУстаревшихВерсиях() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ЕСТЬNULL(СУММА(ВерсииОбъектов.РазмерДанных), 0) КАК РазмерДанных,
	|	КОЛИЧЕСТВО(ВерсииОбъектов.РазмерДанных) КАК КоличествоВерсий
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.ЕстьДанныеВерсии
	|	И &ДополнительныеУсловия";
	
	Запрос = ЗапросПоУстаревшимВерсиям(ТекстЗапроса);
	Выборка = Запрос.Выполнить().Выбрать();
	
	КоличествоВерсий = 0;
	РазмерДанных = 0;
	Если Выборка.Следующий() Тогда
		РазмерДанных = Выборка.РазмерДанных;
		КоличествоВерсий = Выборка.КоличествоВерсий;
	КонецЕсли;
	
	Результат = Новый Структура;
	Результат.Вставить("КоличествоВерсий", КоличествоВерсий);
	Результат.Вставить("РазмерДанных", РазмерДанных);
	Результат.Вставить("РазмерДанныхСтрокой", РазмерДанныхСтрокой(Результат.РазмерДанных));
	
	Возврат Результат;
	
КонецФункции

// См. ИнформацияОбУстаревшихВерсиях.
Функция ЗапросПоУстаревшимВерсиям(ТекстЗапроса)
	
	Запрос = Новый Запрос;
	ГраницыУдаленияОбъектов = ГраницыУдаленияОбъектов();
	ДополнительныеУсловия = "";
	
	Для Индекс = 0 По ГраницыУдаленияОбъектов.Количество() - 1 Цикл
		Если Не ПустаяСтрока(ДополнительныеУсловия) Тогда
			ДополнительныеУсловия = ДополнительныеУсловия + "
			|	ИЛИ";
		КонецЕсли;
		ИндексСтрокой = Формат(Индекс, "ЧН=0; ЧГ=0");
		Условие = "";
		Для Каждого Тип Из ГраницыУдаленияОбъектов[Индекс].СписокТипов Цикл
			Если Не ПустаяСтрока(Условие) Тогда
				Условие = Условие + "
				|	ИЛИ";
			КонецЕсли;
			Условие = Условие + "
			|	ВерсииОбъектов.Объект ССЫЛКА " + Тип;
		КонецЦикла;
		Если ПустаяСтрока(Условие) Тогда
			Продолжить;
		КонецЕсли;
		Условие = "(" + Условие + ")";
		ДополнительныеУсловия = ДополнительныеУсловия + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		"
		|	%1
		|	И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления%2",
		Условие,
		ИндексСтрокой);
		Запрос.УстановитьПараметр("СписокТипов" + ИндексСтрокой, ГраницыУдаленияОбъектов[Индекс].СписокТипов);
		Запрос.УстановитьПараметр("ГраницаУдаления" + ИндексСтрокой, ГраницыУдаленияОбъектов[Индекс].ГраницаУдаления);
	КонецЦикла;
	
	Если ПустаяСтрока(ДополнительныеУсловия) Тогда
		ДополнительныеУсловия = "ЛОЖЬ";
	Иначе
		ДополнительныеУсловия = "(" + ДополнительныеУсловия + ")";
	КонецЕсли;
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДополнительныеУсловия", ДополнительныеУсловия);
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос;
	
КонецФункции

// Строковое представление объемов данных. Например: "1,23 Гб".
Функция РазмерДанныхСтрокой(Знач РазмерДанных)
	
	ЕдиницаИзмерения = НСтр("ru = 'байт'");
	Если 1024 <= РазмерДанных И РазмерДанных < 1024 * 1024 Тогда
		РазмерДанных = РазмерДанных / 1024;
		ЕдиницаИзмерения = НСтр("ru = 'Кб'");
	ИначеЕсли 1024 * 1024 <= РазмерДанных И  РазмерДанных < 1024 * 1024 * 1024 Тогда
		РазмерДанных = РазмерДанных / 1024 / 1024;
		ЕдиницаИзмерения = НСтр("ru = 'Мб'");
	ИначеЕсли 1024 * 1024 * 1024 <= РазмерДанных Тогда
		РазмерДанных = РазмерДанных / 1024 / 1024 / 1024;
		ЕдиницаИзмерения = НСтр("ru = 'Гб'");
	КонецЕсли;
	
	Если РазмерДанных < 10 Тогда
		РазмерДанных = Окр(РазмерДанных, 2);
	ИначеЕсли РазмерДанных < 100 Тогда
		РазмерДанных = Окр(РазмерДанных, 1);
	Иначе
		РазмерДанных = Окр(РазмерДанных, 0);
	КонецЕсли;
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 %2'"), РазмерДанных, ЕдиницаИзмерения);
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Функции для получения отчета по объекту.

// Возвращает сериализованный объект в виде двоичных данных.
//
// Параметры:
//  Объект - Произвольный - сериализуемый объект.
//
// Возвращаемое значение:
//  ДвоичныеДанные - сериализованный объект.
//
Функция СериализоватьОбъект(Объект) Экспорт
	
	ЗаписьXML = Новый ЗаписьFastInfoset;
	ЗаписьXML.УстановитьДвоичныеДанные();
	ЗаписьXML.ЗаписатьОбъявлениеXML();
	
	ЗаписатьXML(ЗаписьXML, Объект, НазначениеТипаXML.Явное);
	
	Возврат ЗаписьXML.Закрыть();

КонецФункции

// Процедура считывает данные XML из файла и заполняет структуры данных.
// 
// Параметры:
//  ДанныеВерсии - ДвоичныеДанные
//               - Структура
//  Ссылка - ЛюбаяСсылка
//
// Возвращаемое значение:
//  Структура:
//   * Реквизиты - ТаблицаЗначений:
//    ** НаименованиеРеквизита - Строка
//    ** ЗначениеРеквизита - Произвольный
//    ** ТипРеквизита - Строка
//    ** Тип - Тип
//   * ТабличныеЧасти - Соответствие из КлючИЗначение:
//    ** Ключ - Строка
//    ** Значение - ТаблицаЗначений
//   * ТабличныеДокументы - см. ВерсионированиеОбъектовПереопределяемый.ПриПолученииТабличныхДокументовОбъекта.ТабличныеДокументы
//   * ДополнительныеРеквизиты - см. ВерсионированиеОбъектовПереопределяемый.ПриПодготовкеДанныхОбъекта.ДополнительныеРеквизиты
//   * СкрываемыеРеквизиты - Массив
//
Функция РазборПредставленияОбъектаXML(ДанныеВерсии, Ссылка) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ТабличныеДокументы");
	Результат.Вставить("ДополнительныеРеквизиты");
	Результат.Вставить("СкрываемыеРеквизиты", Новый Массив);
	
	ДвоичныеДанные = ДанныеВерсии;
	Если ТипЗнч(ДанныеВерсии) = Тип("Структура") Тогда
		ДвоичныеДанные = ДанныеВерсии.Объект;
		ДанныеВерсии.Свойство("ТабличныеДокументы", Результат.ТабличныеДокументы);
		ДанныеВерсии.Свойство("ДополнительныеРеквизиты", Результат.ДополнительныеРеквизиты);
		ДанныеВерсии.Свойство("СкрываемыеРеквизиты", Результат.СкрываемыеРеквизиты);
	КонецЕсли;
	
	ЗначенияРеквизитов = Новый ТаблицаЗначений;
	ЗначенияРеквизитов.Колонки.Добавить("НаименованиеРеквизита");
	ЗначенияРеквизитов.Колонки.Добавить("ЗначениеРеквизита");
	ЗначенияРеквизитов.Колонки.Добавить("ТипРеквизита");
	ЗначенияРеквизитов.Колонки.Добавить("Тип");
	
	ТабличныеЧасти = Новый Соответствие;
	
	ЧтениеXML = Новый ЧтениеFastInfoSet;
	ЧтениеXML.УстановитьДвоичныеДанные(ДвоичныеДанные);
	
	// Уровень позиции маркера в иерархии XML:
	// 0 - уровень не задан
	// 1 - первый элемент (имя объекта)
	// 2 - описание реквизита или табличной части
	// 3 - описание строки табличной части
	// 4 - описание поля строки табличной части.
	УровеньЧтения = 0;
	
	МетаданныеОбъекта = Ссылка.Метаданные();
	ТипЗначенияПоляТЧ = "";
	
	// Основной цикл разбора по XML.
	Пока ЧтениеXML.Прочитать() Цикл
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
			УровеньЧтения = УровеньЧтения + 1;
			Если УровеньЧтения = 1 Тогда // Указатель на первом элементе XML - корень XML.
				// В ЧтениеXML.Имя имя объекта, но оно нам не нужно.
			ИначеЕсли УровеньЧтения = 2 Тогда // Указатель на втором уровне - это реквизит или имя табличной части.
				ИмяРеквизита = ЧтениеXML.Имя;
				
				// Любой реквизит "может оказаться" табличной частью, поэтому на всякий случай его запомним.
				ИмяТабличнойЧасти = ИмяРеквизита;
				Если МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТабличнойЧасти) <> Неопределено Тогда
					ТабличныеЧасти.Вставить(ИмяТабличнойЧасти, Новый ТаблицаЗначений);
				КонецЕсли;
				
				НовоеЗначение = ЗначенияРеквизитов.Добавить();
				НовоеЗначение.НаименованиеРеквизита = ИмяРеквизита;
				
				Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
					Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
						Если ЧтениеXML.ТипУзла = ТипУзлаXML.Атрибут 
							И ЧтениеXML.Имя = "xsi:type" Тогда
								НовоеЗначение.ТипРеквизита = ЧтениеXML.Значение;
								XMLТип = ЧтениеXML.Значение;
								Если СтрНачинаетсяС(XMLТип, "xs:") Тогда
									НовоеЗначение.Тип = ИзXMLТипа(Новый ТипДанныхXML(Прав(XMLТип, СтрДлина(XMLТип)-3), "http://www.w3.org/2001/XMLSchema"));
								Иначе
									НовоеЗначение.Тип = ИзXMLТипа(Новый ТипДанныхXML(XMLТип, ""));
								КонецЕсли;
						КонецЕсли;
					КонецЦикла;
				КонецЕсли;
				
				Если Не ЗначениеЗаполнено(НовоеЗначение.Тип) Тогда
					ОписаниеРеквизита = МетаданныеРеквизита(МетаданныеОбъекта, ИмяРеквизита);
					Если ОписаниеРеквизита = Неопределено Тогда
						ОписаниеРеквизита = Метаданные.ОбщиеРеквизиты.Найти(ИмяРеквизита);
					КонецЕсли;
					Если ОписаниеРеквизита = Неопределено И Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
						ОписаниеРеквизита = МетаданныеОбъекта.ПризнакиУчета.Найти(ИмяРеквизита);
					КонецЕсли;
					
					Если ОписаниеРеквизита <> Неопределено
						И ОписаниеРеквизита.Тип.Типы().Количество() = 1 Тогда
						НовоеЗначение.Тип = ОписаниеРеквизита.Тип.Типы()[0];
					КонецЕсли;
				КонецЕсли;
			ИначеЕсли (УровеньЧтения = 3) И ЧтениеXML.Имя = "Row" Тогда // Указатель на поле табличной части.
				Если ТабличныеЧасти[ИмяТабличнойЧасти] = Неопределено Тогда
					ТабличныеЧасти.Вставить(ИмяТабличнойЧасти, Новый ТаблицаЗначений);
				КонецЕсли;
				ТабличныеЧасти[ИмяТабличнойЧасти].Добавить();
			ИначеЕсли УровеньЧтения = 4 Тогда
				Если ЧтениеXML.Имя = "v8:Type" Тогда
					Если НовоеЗначение.ЗначениеРеквизита = Неопределено Тогда
						НовоеЗначение.ЗначениеРеквизита = "";
					КонецЕсли;
				Иначе // Указатель на поле табличной части.
					ТипЗначенияПоляТЧ = "";
					ИмяПоляТЧ = ЧтениеXML.Имя;
					Таблица   = ТабличныеЧасти[ИмяТабличнойЧасти];// ТаблицаЗначений 
					Если Таблица.Колонки.Найти(ИмяПоляТЧ)= Неопределено Тогда
						Таблица.Колонки.Добавить(ИмяПоляТЧ);
					КонецЕсли;
					
					Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
						Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
							Если ЧтениеXML.ТипУзла = ТипУзлаXML.Атрибут 
								И ЧтениеXML.Имя = "xsi:type" Тогда
									XMLТип = ЧтениеXML.Значение;
									Если СтрНачинаетсяС(XMLТип, "xs:") Тогда
										ТипЗначенияПоляТЧ = ИзXMLТипа(Новый ТипДанныхXML(Прав(XMLТип, СтрДлина(XMLТип)-3), "http://www.w3.org/2001/XMLSchema"));
									Иначе
										ТипЗначенияПоляТЧ = ИзXMLТипа(Новый ТипДанныхXML(XMLТип, ""));
									КонецЕсли;
							КонецЕсли;
						КонецЦикла;
					КонецЕсли;
				КонецЕсли;
			КонецЕсли;
		ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
			УровеньЧтения = УровеньЧтения - 1;
		ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
			Если (УровеньЧтения = 2) Тогда // значение реквизита
				Попытка
					НовоеЗначение.ЗначениеРеквизита = ?(ЗначениеЗаполнено(НовоеЗначение.Тип), XMLЗначение(НовоеЗначение.Тип, ЧтениеXML.Значение), ЧтениеXML.Значение);
				Исключение
					НовоеЗначение.ЗначениеРеквизита = ЧтениеXML.Значение;
				КонецПопытки;
			ИначеЕсли (УровеньЧтения = 4) Тогда // значение реквизита
				Если НовоеЗначение.Тип = Тип("ОписаниеТипов") Тогда
					ТипСтрокой = Строка(ИзXMLТипа(Новый ТипДанныхXML(ЧтениеXML.Значение, "")));
					Если ПустаяСтрока(ТипСтрокой) Тогда
						ТипСтрокой = ЧтениеXML.Значение;
					КонецЕсли;
					Если Не ПустаяСтрока(НовоеЗначение.ЗначениеРеквизита) Тогда
						НовоеЗначение.ЗначениеРеквизита = НовоеЗначение.ЗначениеРеквизита + Символы.ПС;
					КонецЕсли;
					НовоеЗначение.ЗначениеРеквизита = НовоеЗначение.ЗначениеРеквизита + ТипСтрокой;
				Иначе
					Если ТипЗначенияПоляТЧ = "" Тогда
						ОписаниеРеквизита = Неопределено;
						МетаданныеТабличнойЧасти = МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТабличнойЧасти);
						Если МетаданныеТабличнойЧасти <> Неопределено Тогда
							ОписаниеРеквизита = МетаданныеРеквизитаТабличнойЧасти(МетаданныеТабличнойЧасти, ИмяПоляТЧ);
							Если ОписаниеРеквизита = Неопределено И Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
								ОписаниеРеквизита = МетаданныеОбъекта.ПризнакиУчетаСубконто.Найти(ИмяПоляТЧ);
							КонецЕсли;
							Если ОписаниеРеквизита <> Неопределено
								И ОписаниеРеквизита.Тип.Типы().Количество() = 1 Тогда
									ТипЗначенияПоляТЧ = ОписаниеРеквизита.Тип.Типы()[0];
							КонецЕсли;
						КонецЕсли;
					КонецЕсли;
					ПоследняяСтрока = ТабличныеЧасти[ИмяТабличнойЧасти].Получить(ТабличныеЧасти[ИмяТабличнойЧасти].Количество()-1);
					Значение = ЧтениеXML.Значение;
					Если ЗначениеЗаполнено(ТипЗначенияПоляТЧ) Тогда
						Попытка
							Значение = XMLЗначение(ТипЗначенияПоляТЧ, ЧтениеXML.Значение);
						Исключение
							Значение = ЧтениеXML.Значение;
						КонецПопытки;
					КонецЕсли;
					ПоследняяСтрока[ИмяПоляТЧ] = Значение;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	// Из списка реквизитов исключаем табличные части.
	Для Каждого Элемент Из ТабличныеЧасти Цикл
		ЗначенияРеквизитов.Удалить(ЗначенияРеквизитов.Найти(Элемент.Ключ));
	КонецЦикла;
	
	// Заполнение колонок таблицы в случае, когда в объекте табличная часть пустая, и имена колонок не были прочитаны.
	Для Каждого ТабличнаяЧасть Из ТабличныеЧасти Цикл
		ИмяТаблицы = ТабличнаяЧасть.Ключ;  // Строка - 
		Таблица = ТабличнаяЧасть.Значение; // ТаблицаЗначений - 
		Если Таблица.Колонки.Количество() = 0 Тогда
			МетаданныеТаблицы = МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТаблицы);
			Если МетаданныеТаблицы <> Неопределено Тогда
				Для Каждого ОписаниеКолонки Из РеквизитыТабличнойЧасти(МетаданныеТаблицы) Цикл
					Если Таблица.Колонки.Найти(ОписаниеКолонки.Имя)= Неопределено Тогда
						Таблица.Колонки.Добавить(ОписаниеКолонки.Имя);
					КонецЕсли;
				КонецЦикла;
				Если Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
					Для Каждого ОписаниеКолонки Из МетаданныеОбъекта.ПризнакиУчетаСубконто Цикл
						Если Таблица.Колонки.Найти(ОписаниеКолонки.Имя)= Неопределено Тогда
							Таблица.Колонки.Добавить(ОписаниеКолонки.Имя);
						КонецЕсли;
					КонецЦикла;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Результат.Вставить("Реквизиты", ЗначенияРеквизитов);
	Результат.Вставить("ТабличныеЧасти", ТабличныеЧасти);
	
	Если Результат.СкрываемыеРеквизиты <> Неопределено Тогда
		Для Каждого ИмяРеквизита Из Результат.СкрываемыеРеквизиты Цикл
			Если СтрЗаканчиваетсяНа(ИмяРеквизита, ".*") Тогда
				ИмяТабличнойЧасти = Лев(ИмяРеквизита, СтрДлина(ИмяРеквизита) - 2);
				Если Результат.ТабличныеЧасти[ИмяТабличнойЧасти] <> Неопределено Тогда
					Результат.ТабличныеЧасти.Удалить(ИмяТабличнойЧасти);
				КонецЕсли;
			Иначе
				НайденныеРеквизиты = Результат.Реквизиты.НайтиСтроки(Новый Структура("НаименованиеРеквизита", ИмяРеквизита));
				Для Каждого Реквизит Из НайденныеРеквизиты Цикл
					Результат.Реквизиты.Удалить(Реквизит);
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Если Результат.ДополнительныеРеквизиты <> Неопределено Тогда
		Для Каждого ДополнительныйРеквизит Из Результат.ДополнительныеРеквизиты Цикл
			Реквизит = ЗначенияРеквизитов.Добавить();
			Реквизит.НаименованиеРеквизита = ДополнительныйРеквизит.Наименование;
			Реквизит.ЗначениеРеквизита = ДополнительныйРеквизит.Значение;
			Реквизит.Тип = ТипЗнч(ДополнительныйРеквизит.Значение);
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  МетаданныеОбъекта - ОбъектМетаданных
//  ИмяРеквизита - Строка
// Возвращаемое значение:
//  ОписаниеСтандартногоРеквизита, ОбъектМетаданныхРеквизит, Неопределено
//
Функция МетаданныеРеквизита(МетаданныеОбъекта, ИмяРеквизита)
	Результат = МетаданныеОбъекта.Реквизиты.Найти(ИмяРеквизита);
	Если Результат = Неопределено Тогда
		Попытка
			Результат = МетаданныеОбъекта.СтандартныеРеквизиты[ИмяРеквизита];
		Исключение
			Результат = Неопределено;
		КонецПопытки;
	КонецЕсли;
	Возврат Результат;
КонецФункции

Функция МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТабличнойЧасти) Экспорт
	
	ТабличнаяЧасть = МетаданныеОбъекта.ТабличныеЧасти.Найти(ИмяТабличнойЧасти);
	Если ТабличнаяЧасть <> Неопределено Тогда
		Возврат ТабличнаяЧасть;
	КонецЕсли;
	
	Если Не Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта)
		И Не Метаданные.ПланыВидовРасчета.Содержит(МетаданныеОбъекта) Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Попытка
		ТабличнаяЧасть = МетаданныеОбъекта.СтандартныеТабличныеЧасти[ИмяТабличнойЧасти];
	Исключение
		ТабличнаяЧасть = Неопределено;
	КонецПопытки;
	
	Возврат ТабличнаяЧасть;
	
КонецФункции

Функция МетаданныеРеквизитаТабличнойЧасти(МетаданныеТабличнойЧасти, ИмяРеквизита) Экспорт
	Результат = Неопределено;
	Если ТипЗнч(МетаданныеТабличнойЧасти) = Тип("ОписаниеСтандартнойТабличнойЧасти") Тогда
		Попытка
			Результат = МетаданныеТабличнойЧасти.СтандартныеРеквизиты[ИмяРеквизита];
		Исключение
			Результат = Неопределено;
		КонецПопытки;
	Иначе
		Результат = МетаданныеТабличнойЧасти.Реквизиты.Найти(ИмяРеквизита);
	КонецЕсли;
	Возврат Результат;
КонецФункции

// Параметры:
//  МетаданныеТабличнойЧасти - ОписаниеСтандартнойТабличнойЧасти
//                           - ОбъектМетаданныхТабличнаяЧасть
//  
// Возвращаемое значение:
//  ОписанияСтандартныхРеквизитов, КоллекцияОбъектовМетаданных
//
Функция РеквизитыТабличнойЧасти(МетаданныеТабличнойЧасти)
	Если ТипЗнч(МетаданныеТабличнойЧасти) = Тип("ОписаниеСтандартнойТабличнойЧасти") Тогда
		Результат = МетаданныеТабличнойЧасти.СтандартныеРеквизиты;
	Иначе
		Результат = МетаданныеТабличнойЧасти.Реквизиты;
	КонецЕсли;
	Возврат Результат;
КонецФункции

Функция СформироватьОтчетПоВерсииОбъекта(ОписаниеОбъекта, СсылкаНаОбъект)
	
	Если СсылкаНаОбъект.Метаданные().Макеты.Найти("МакетОбъекта") <> Неопределено Тогда
		Макет = ОбщегоНазначения.МенеджерОбъектаПоСсылке(СсылкаНаОбъект).ПолучитьМакет("МакетОбъекта");
		Возврат СформироватьПоСтандартномуМакету(Макет, ОписаниеОбъекта, ОписаниеОбъекта.Описание, СсылкаНаОбъект);
	Иначе
		ТабличныйДокумент = Новый ТабличныйДокумент;
		Секция = ТабличныйДокумент.ПолучитьОбласть("R2");
		ВывестиТекстВОтчет(ТабличныйДокумент, Секция, "R2C2", СсылкаНаОбъект.Метаданные().Синоним, ШрифтыСтиля.ОченьКрупныйШрифтТекста);
		
		ТабличныйДокумент.Область("C2").ШиринаКолонки = 30;
		Если ОписаниеОбъекта.НомерВерсии <> 0 Тогда
			ВывестиШапкуПоВерсии(ТабличныйДокумент, ОписаниеОбъекта.Описание, 4, 3);
			ВывестиШапкуПоВерсии(ТабличныйДокумент, ОписаниеОбъекта.Комментарий, 5, 3);
		КонецЕсли;
		
		ЧислоВыведенныхСтрок = ВывестиРеквизитыПоРазобранномуОбъекту(ТабличныйДокумент, ОписаниеОбъекта, СсылкаНаОбъект);
		ВывестиТабличныеЧастиПоРазобранномуОбъекту(ТабличныйДокумент, ОписаниеОбъекта, ЧислоВыведенныхСтрок + 7, СсылкаНаОбъект);
		ВывестиТабличныеДокументыПоРазобранномуОбъекту(ТабличныйДокумент, ОписаниеОбъекта);
		Возврат ТабличныйДокумент;
	КонецЕсли;
	
КонецФункции

Функция СформироватьПоСтандартномуМакету(Макет, ВерсияОбъекта, Знач ОписаниеВерсии, СсылкаНаОбъект)
	
	Результат = Новый ТабличныйДокумент;
	МетаданныеОбъекта = СсылкаНаОбъект.Метаданные();
	НаименованиеОбъекта = МетаданныеОбъекта.Имя;
	Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(СсылкаНаОбъект)) Тогда
		Макет = Справочники[НаименованиеОбъекта].ПолучитьМакет("МакетОбъекта");
	Иначе
		Макет = Документы[НаименованиеОбъекта].ПолучитьМакет("МакетОбъекта");
	КонецЕсли;
	
	// Заголовок
	Область = Макет.ПолучитьОбласть("Заголовок");
	Результат.Вывести(Область);
	
	Область = Результат.ПолучитьОбласть("R3");
	УстановитьСвойстваТекста(Область.Область("R1C2"), ОписаниеВерсии, ШрифтыСтиля.ВажнаяНадписьШрифт);
	Результат.Вывести(Область);
	
	Область = Результат.ПолучитьОбласть("R5");
	Результат.Вывести(Область);
	
	// Шапка
	Шапка = Макет.ПолучитьОбласть("Шапка");
	Реквизиты = Новый Структура;
	Для Каждого ОписаниеРеквизита Из ВерсияОбъекта.Реквизиты Цикл
		ИмяРеквизита = ОписаниеРеквизита.НаименованиеРеквизита;
		МетаданныеРеквизита = МетаданныеРеквизита(МетаданныеОбъекта, ОписаниеРеквизита.НаименованиеРеквизита);
		Если МетаданныеРеквизита = Неопределено И Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
			МетаданныеРеквизита = МетаданныеОбъекта.ПризнакиУчета.Найти(ОписаниеРеквизита.НаименованиеРеквизита);
		КонецЕсли;
		Если МетаданныеРеквизита <> Неопределено Тогда
			ИмяРеквизита = МетаданныеРеквизита.Имя;
		КонецЕсли;
		
		ЗначениеРеквизита = ОписаниеРеквизита.ЗначениеРеквизита;
		Реквизиты.Вставить(ИмяРеквизита, ЗначениеРеквизита);
	КонецЦикла;
	Шапка.Параметры.Заполнить(Реквизиты);
	Результат.Вывести(Шапка);
	
	ИменаТабличныхЧастей = Новый Массив;
	Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.ТабличныеЧасти Цикл
		ИменаТабличныхЧастей.Добавить(ТабличнаяЧасть.Имя);
	КонецЦикла;
	Если Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
		Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.СтандартныеТабличныеЧасти Цикл
			ИменаТабличныхЧастей.Добавить(ТабличнаяЧасть.Имя);
		КонецЦикла;
	КонецЕсли;
	
	Для Каждого ИмяТабличнойЧасти Из ИменаТабличныхЧастей Цикл
		Если ВерсияОбъекта.ТабличныеЧасти[ИмяТабличнойЧасти].Количество() = 0 Тогда
			Продолжить;
		КонецЕсли;
		
		ТабличнаяЧасть = ВерсияОбъекта.ТабличныеЧасти[ИмяТабличнойЧасти].Скопировать(); // ТаблицаЗначений
		ТабличнаяЧасть.Колонки.Добавить("НомерСтроки");
		
		ИмяОбласти = ИмяТабличнойЧасти + "Шапка";
		Если Макет.Области.Найти(ИмяОбласти) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Область = Макет.ПолучитьОбласть(ИмяОбласти);
		Результат.Вывести(Область);
		
		ИмяОбласти = ИмяТабличнойЧасти;
		Если Макет.Области.Найти(ИмяОбласти) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Область = Макет.ПолучитьОбласть(ИмяОбласти);
		НомерСтроки = 0;
		Для Каждого СтрокаТаблицы Из ТабличнаяЧасть Цикл
			НомерСтроки = НомерСтроки + 1;
			СтрокаТаблицы.НомерСтроки = НомерСтроки;
			Область.Параметры.Заполнить(СтрокаТаблицы);
			Результат.Вывести(Область);
		КонецЦикла;
	КонецЦикла;
	
	Если ВерсияОбъекта.Свойство("ТабличныеДокументы") Тогда
		ТабличныеДокументы = ВерсияОбъекта.ТабличныеДокументы;// см. ТабличныеДокументыОбъекта
		Если ТабличныеДокументы <> Неопределено Тогда
			Если Макет.Области.Найти("ШапкаТабличныхДокументов") <> Неопределено Тогда
				ШапкаТабличныхДокументов = Макет.ПолучитьОбласть("ШапкаТабличныхДокументов");
				Результат.Вывести(ШапкаТабличныхДокументов);
				ШапкаТабличногоДокумента = ?(Макет.Области.Найти("ШапкаТабличногоДокумента") = Неопределено,
					Неопределено, Макет.ПолучитьОбласть("ШапкаТабличногоДокумента"));
				
				Для Каждого ЭлементСтруктуры Из ТабличныеДокументы Цикл
					Если ШапкаТабличногоДокумента <> Неопределено Тогда
						НаименованиеТабличногоДокумента = Новый Структура("НаименованиеТабличногоДокумента", ЭлементСтруктуры.Значение.Наименование);
						ШапкаТабличногоДокумента.Параметры.Заполнить(НаименованиеТабличногоДокумента);
						Результат.Вывести(ШапкаТабличногоДокумента);
					КонецЕсли;
					Результат.Вывести(ЭлементСтруктуры.Значение.Данные);
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Результат.ОтображатьСетку = Ложь;
	Результат.Защита = Истина;
	Результат.ТолькоПросмотр = Истина;
	Результат.ОтображатьЗаголовки = Ложь;
	
	Возврат Результат;
	
КонецФункции

Процедура ВывестиШапкуПоВерсии(Результат, Знач Текст, Знач НомерСтроки, Знач НомерКолонки)
	
	Если Не ПустаяСтрока(Текст) Тогда
		
		Результат.Область("C" + Строка(НомерКолонки)).ШиринаКолонки = 50;
		
		Регион = "R" + Формат(НомерСтроки, "ЧГ=0") + "C" + Формат(НомерКолонки, "ЧГ=0");
		Результат.Область(Регион).Текст = Текст;
		Результат.Область(Регион).ЦветФона = ЦветаСтиля.ТекстЗапрещеннойЯчейкиЦвет;
		Результат.Область(Регион).Шрифт = ШрифтыСтиля.ВажнаяНадписьШрифт;
		Результат.Область(Регион).ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
		Результат.Область(Регион).ГраницаСнизу  = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
		Результат.Область(Регион).ГраницаСлева  = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
		Результат.Область(Регион).ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
		
	КонецЕсли;
	
КонецПроцедуры

Функция ВывестиРеквизитыПоРазобранномуОбъекту(Результат, ВерсияОбъекта, СсылкаНаОбъект)
	
	Секция = Результат.ПолучитьОбласть("R6");
	ВывестиТекстВОтчет(Результат, Секция, "R1C1:R1C3", " ");
	ВывестиТекстВОтчет(Результат, Секция, "R1C2", "Реквизиты", ШрифтыСтиля.КрупныйШрифтТекста);
	Результат.НачатьГруппуСтрок("ГруппаРеквизитов");
	ВывестиТекстВОтчет(Результат, Секция, "R1C1:R1C3", " ");
	
	ЧислоВыводимыхСтрок = 0;
	
	Реквизиты = ВерсияОбъекта.Реквизиты.Скопировать();
	Реквизиты.Колонки.Добавить("СтруктураОписанияНаименования");
	Реквизиты.Колонки.Добавить("ВыводимоеНаименование");
	Для Каждого Реквизит Из Реквизиты Цикл
		Реквизит.СтруктураОписанияНаименования = НаименованиеВыводимогоРеквизита(СсылкаНаОбъект, Реквизит.НаименованиеРеквизита);
		Реквизит.ВыводимоеНаименование = Реквизит.СтруктураОписанияНаименования.ВыводимоеНаименование;
	КонецЦикла;
	Реквизиты.Сортировать("ВыводимоеНаименование");
	
	Для Каждого ЭлементРеквизит Из Реквизиты Цикл
		СтруктураОписанияНаименования = ЭлементРеквизит.СтруктураОписанияНаименования;
		Если Не СтруктураОписанияНаименования.ВыводитьРеквизит Тогда
			Продолжить;
		КонецЕсли;
		
		ВыводимоеНаименование = СтруктураОписанияНаименования.ВыводимоеНаименование;
		ОписаниеРеквизита = СтруктураОписанияНаименования.ОписаниеРеквизита;
		
		ЗначениеРеквизита = ?(ЭлементРеквизит.ЗначениеРеквизита = Неопределено, "", ЭлементРеквизит.ЗначениеРеквизита);
		ПредставлениеЗначения = ПредставлениеЗначенияРеквизита(ЗначениеРеквизита, ОписаниеРеквизита);
		
		УстановитьСвойстваТекста(Секция.Область("R1C2"), ВыводимоеНаименование, ШрифтыСтиля.ВажнаяНадписьШрифт);
		УстановитьСвойстваТекста(Секция.Область("R1C3"), ПредставлениеЗначения);
		Секция.Область("R1C2:R1C3").ГраницаСнизу = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1, 0);
		Секция.Область("R1C2:R1C3").ЦветРамки = ЦветаСтиля.ТекстЗапрещеннойЯчейкиЦвет;
		
		Результат.Вывести(Секция);
		
		ЧислоВыводимыхСтрок = ЧислоВыводимыхСтрок + 1;
	КонецЦикла;
	
	Результат.ЗакончитьГруппуСтрок();
	
	Возврат ЧислоВыводимыхСтрок;
	
КонецФункции

Процедура ВывестиТабличныеЧастиПоРазобранномуОбъекту(Результат, ВерсияОбъекта, НомерСтрокиВывода, СсылкаНаОбъект)
	
	Если ВерсияОбъекта.ТабличныеЧасти.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	МетаданныеОбъекта = СсылкаНаОбъект.Метаданные();
	ЧислоВыводимыхСтрок = 0;
	
	Для Каждого СтрокаТабличнаяЧасть Из ВерсияОбъекта.ТабличныеЧасти Цикл
		НаименованиеТабличнойЧасти = СтрокаТабличнаяЧасть.Ключ;
		ТабличнаяЧасть = СтрокаТабличнаяЧасть.Значение; // ТаблицаЗначений
		Если ТабличнаяЧасть.Количество() = 0 Тогда
			Продолжить;
		КонецЕсли;
			
		МетаданныеТЧ = МетаданныеТабличнойЧасти(МетаданныеОбъекта, НаименованиеТабличнойЧасти);
		СинонимТЧ = НаименованиеТабличнойЧасти;
		Если МетаданныеТЧ <> Неопределено Тогда
			СинонимТЧ = МетаданныеТЧ.Представление();
		КонецЕсли;
		
		Секция = Результат.ПолучитьОбласть("R" + XMLСтрока(Результат.ВысотаТаблицы + 1));
		ВывестиТекстВОтчет(Результат, Секция, "R1C1:R1C" + Формат(ТабличнаяЧасть.Колонки.Количество(), "ЧГ=0"), " ");
		ОбластьВывода = ВывестиТекстВОтчет(Результат, Секция, "R1C2", СинонимТЧ, ШрифтыСтиля.КрупныйШрифтТекста);
		Результат.Область("R" + Формат(ОбластьВывода.Верх, "ЧГ=0") + "C2").СоздатьФорматСтрок();
		Результат.Область("R" + Формат(ОбластьВывода.Верх, "ЧГ=0") + "C2").ШиринаКолонки = Окр(СтрДлина(СинонимТЧ)*2, 0, РежимОкругления.Окр15как20);
		Результат.НачатьГруппуСтрок("ГруппаСтрок");
		
		ВывестиТекстВОтчет(Результат, Секция, "R1C1:R1C3", " ");
		ЧислоВыводимыхСтрок = ЧислоВыводимыхСтрок + 1;
		НомерСтрокиВывода = НомерСтрокиВывода + 3;
		
		ДобавляемаяТЧ = Новый ТабличныйДокумент;
		ДобавляемаяТЧ.Присоединить(СформироватьПустойСектор(ТабличнаяЧасть.Количество()+1));
		
		НомерКолонки = 2;
		СоответствиеРазмерностиКолонок = Новый Соответствие;
		
		Секция = Новый ТабличныйДокумент;
		ОбластьСекции = Секция.Область("R1C1");
		УстановитьСвойстваТекста(ОбластьСекции, "N", ШрифтыСтиля.ВажнаяНадписьШрифт, Истина);
		ОбластьСекции.ЦветФона = ЦветаСтиля.ТекстЗапрещеннойЯчейкиЦвет;
		
		НомерСтроки = 1;
		Для Каждого СтрокаТабличнойЧасти Из ТабличнаяЧасть Цикл
			НомерСтроки = НомерСтроки + 1;
			УстановитьСвойстваТекста(Секция.Область("R" + Формат(НомерСтроки, "ЧГ=0") + "C1"), 
				Формат(НомерСтроки-1, "ЧГ=0"), , Истина);
		КонецЦикла;
		ДобавляемаяТЧ.Присоединить(Секция);
		
		НомерКолонки = 3;
		
		Для Каждого КолонкаТабличнойЧасти Из ТабличнаяЧасть.Колонки Цикл
			Секция = Новый ТабличныйДокумент;
			НаименованиеПоля = КолонкаТабличнойЧасти.Имя;
			
			ОписаниеПоля = Неопределено;
			Если МетаданныеТЧ <> Неопределено Тогда
				ОписаниеПоля = МетаданныеРеквизитаТабличнойЧасти(МетаданныеТЧ, НаименованиеПоля);
			КонецЕсли;
			Если ОписаниеПоля = Неопределено И Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
				ОписаниеПоля = МетаданныеОбъекта.ПризнакиУчетаСубконто.Найти(НаименованиеПоля);
			КонецЕсли;
			Если ОписаниеПоля = Неопределено Тогда
				ВыводимоеНаименованиеПоля = НаименованиеПоля;
			Иначе
				ВыводимоеНаименованиеПоля = ОписаниеПоля.Представление();
			КонецЕсли;
			
			ЦветЗаголовкаКолонки = ?(ОписаниеПоля = Неопределено, ЦветаСтиля.ЗаголовокУдаленногоРеквизитаФон, ЦветаСтиля.ТекстЗапрещеннойЯчейкиЦвет);
			СекцияОбласти = Секция.Область("R1C1");
			УстановитьСвойстваТекста(СекцияОбласти, ВыводимоеНаименованиеПоля, ШрифтыСтиля.ВажнаяНадписьШрифт, Истина);
			СекцияОбласти.ЦветФона = ЦветЗаголовкаКолонки;
			СоответствиеРазмерностиКолонок.Вставить(НомерКолонки, СтрДлина(НаименованиеПоля) + 4);
			НомерСтроки = 1;
			Для Каждого СтрокаТабличнойЧасти Из ТабличнаяЧасть Цикл
				НомерСтроки = НомерСтроки + 1;
				Значение = ?(СтрокаТабличнойЧасти[НаименованиеПоля] = Неопределено, "", СтрокаТабличнойЧасти[НаименованиеПоля]);
				ПредставлениеЗначения = ПредставлениеЗначенияРеквизита(Значение, ОписаниеПоля);
				
				УстановитьСвойстваТекста(Секция.Область("R" + Формат(НомерСтроки, "ЧГ=0") + "C1"), ПредставлениеЗначения, , Истина);
				Если СтрДлина(ПредставлениеЗначения) > (СоответствиеРазмерностиКолонок[НомерКолонки] - 4) Тогда
					СоответствиеРазмерностиКолонок[НомерКолонки] = СтрДлина(ПредставлениеЗначения) + 4;
				КонецЕсли;
			КонецЦикла;
			
			ДобавляемаяТЧ.Присоединить(Секция);
			НомерКолонки = НомерКолонки + 1;
		КонецЦикла;
		
		ОбластьВывода = Результат.Вывести(ДобавляемаяТЧ);
		Результат.Область(ОбластьВывода.Верх, 1, ОбластьВывода.Низ, НомерКолонки).СоздатьФорматСтрок();
		Результат.Область("R" + Формат(ОбластьВывода.Верх, "ЧГ=0") + "C2").ШиринаКолонки = 7;
		Для ТекущийНомерКолонки = 3 По НомерКолонки-1 Цикл
			Результат.Область("R" + Формат(ОбластьВывода.Верх, "ЧГ=0") + "C" + Формат(ТекущийНомерКолонки, "ЧГ=0")).ШиринаКолонки = СоответствиеРазмерностиКолонок[ТекущийНомерКолонки];
		КонецЦикла;
		Результат.ЗакончитьГруппуСтрок();
	КонецЦикла;
	
КонецПроцедуры

Функция ВывестиТекстВОтчет(Результат, Знач Секция, Знач Регион, Знач Текст, Знач Шрифт = Неопределено)
	
	Если Шрифт = Неопределено Тогда
		Шрифт = ШрифтыСтиля.ШрифтТекста;
	КонецЕсли;
	
	ОбластьСекции = Секция.Область(Регион);
	
	Если ТипЗнч(ОбластьСекции) = Тип("ОбластьЯчеекТабличногоДокумента") Тогда
	
		ОбластьСекции.Текст = Текст;
		ОбластьСекции.Шрифт = Шрифт;
		ОбластьСекции.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Лево;
		
		ОбластьСекции.ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.НетЛинии);
		ОбластьСекции.ГраницаСнизу  = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.НетЛинии);
		ОбластьСекции.ГраницаСлева  = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.НетЛинии);
		ОбластьСекции.ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.НетЛинии);
		
	КонецЕсли;
	
	Возврат Результат.Вывести(Секция);
	
КонецФункции

Процедура УстановитьСвойстваТекста(ОбластьСекции, Текст, Знач Шрифт = Неопределено, Знач ПоказыватьГраницы = Ложь)
	
	Если Шрифт = Неопределено Тогда
		Шрифт = ШрифтыСтиля.ШрифтТекста;
	КонецЕсли;
	
	Если ТипЗнч(ОбластьСекции) = Тип("ОбластьЯчеекТабличногоДокумента") Тогда
	
		ОбластьСекции.Текст = Текст;
		ОбластьСекции.Шрифт = Шрифт;
		
		Если ПоказыватьГраницы Тогда
			ОбластьСекции.ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
			ОбластьСекции.ГраницаСнизу  = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
			ОбластьСекции.ГраницаСлева  = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
			ОбластьСекции.ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
			ОбластьСекции.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
		КонецЕсли;
	
	КонецЕсли
	
КонецПроцедуры

Функция СформироватьПустойСектор(Знач ЧислоСтрок, Знач ТипВывода = "")
	
	ЗначениеЗаполнения = Новый Массив;
	
	Для Индекс = 1 По ЧислоСтрок Цикл
		ЗначениеЗаполнения.Добавить(" ");
	КонецЦикла;
	
	Возврат СформироватьСекторСтрокиТЧ(ЗначениеЗаполнения, ТипВывода);
	
КонецФункции

// Параметры:
//  ЗначениеЗаполнения - Массив из Строка.
//  ТипВывода - Строка.
//
Функция СформироватьСекторСтрокиТЧ(Знач ЗначениеЗаполнения,Знач ТипВывода = "")
	
	ОбщийШаблон = РегистрыСведений.ВерсииОбъектов.ПолучитьМакет("СтандартныйМакетПредставленияОбъекта");
	
	ТабличныйДокумент = Новый ТабличныйДокумент;
	
	Если ТипВывода = ""  Тогда
		Шаблон = ОбщийШаблон.ПолучитьОбласть("ИсходноеЗначениеРеквизита");
	ИначеЕсли ТипВывода = "И" Тогда
		Шаблон = ОбщийШаблон.ПолучитьОбласть("ИзмененноеЗначениеРеквизита");
	ИначеЕсли ТипВывода = "Д" Тогда
		Шаблон = ОбщийШаблон.ПолучитьОбласть("ДобавленныйРеквизит");
	ИначеЕсли ТипВывода = "У" Тогда
		Шаблон = ОбщийШаблон.ПолучитьОбласть("УдаленныйРеквизит");
	КонецЕсли;
	
	Для Каждого ОчередноеЗначение Из ЗначениеЗаполнения Цикл
		Шаблон.Параметры.ЗначениеРеквизита = ОчередноеЗначение;
		ТабличныйДокумент.Вывести(Шаблон);
	КонецЦикла;
	
	Возврат ТабличныйДокумент;
	
КонецФункции

Функция ПредставлениеЗначенияРеквизита(ЗначениеРеквизита, ОбъектМетаданныхРеквизит)
	
	ФорматнаяСтрока = "";
	Если ОбъектМетаданныхРеквизит <> Неопределено Тогда
		Если ТипЗнч(ЗначениеРеквизита) = Тип("Дата") Тогда
			ФорматнаяСтрока = "ДЛФ=DT";
			Если ОбъектМетаданныхРеквизит.Тип.КвалификаторыДаты.ЧастиДаты = ЧастиДаты.Дата Тогда
				ФорматнаяСтрока = "ДЛФ=D";
			ИначеЕсли ОбъектМетаданныхРеквизит.Тип.КвалификаторыДаты.ЧастиДаты = ЧастиДаты.Время Тогда
				ФорматнаяСтрока = "ДЛФ=T";
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Формат(ЗначениеРеквизита, ФорматнаяСтрока);
	
КонецФункции

Функция РазборВерсии(Ссылка, НомерВерсии) Экспорт
	
	СведенияОВерсии = СведенияОВерсииОбъекта(Ссылка, НомерВерсии);
	
	Результат = РазборПредставленияОбъектаXML(СведенияОВерсии.ВерсияОбъекта, Ссылка);
	Результат.Вставить("ИмяОбъекта",     Строка(Ссылка));
	Результат.Вставить("АвторИзменения", СокрЛП(Строка(СведенияОВерсии.АвторВерсии)));
	Результат.Вставить("ДатаИзменения",  СведенияОВерсии.ДатаВерсии);
	Результат.Вставить("Комментарий",    СведенияОВерсии.Комментарий);
	
	ВерсионированиеОбъектовПереопределяемый.ПослеРазбораВерсииОбъекта(Ссылка, Результат);
	
	Возврат Результат;
	
КонецФункции

Процедура ВывестиТабличныеДокументыПоРазобранномуОбъекту(ТабличныйДокумент, ОписаниеОбъекта)
	
	ТабличныеДокументы = ОписаниеОбъекта.ТабличныеДокументы;// см. ТабличныеДокументыОбъекта
	
	Если ТабличныеДокументы = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ОбщийШаблон = РегистрыСведений.ВерсииОбъектов.ПолучитьМакет("СтандартныйМакетПредставленияОбъекта");
	
	ШаблонЗаголовокТабличныеДокументы = ОбщийШаблон.ПолучитьОбласть("ШапкаТабличныхДокументов");	
	ШаблонСтрокаТабличныеДокументы = ОбщийШаблон.ПолучитьОбласть("ШапкаТабличногоДокумента");
	ШаблонПустаяСтрока = ОбщийШаблон.ПолучитьОбласть("СвободнаяСтрока");
	
	ТабличныйДокумент.Вывести(ШаблонПустаяСтрока);
	ТабличныйДокумент.Вывести(ШаблонЗаголовокТабличныеДокументы);
	ТабличныйДокумент.Вывести(ШаблонПустаяСтрока);
	ТабличныйДокумент.НачатьГруппуСтрок("ГруппаТабличныхДокументов");
	
	Для Каждого ЭлементСтруктуры Из ТабличныеДокументы Цикл
		НаименованиеТабличногоДокумента = ЭлементСтруктуры.Значение.Наименование;
		ШаблонСтрокаТабличныеДокументы.Параметры.НаименованиеТабличногоДокумента = НаименованиеТабличногоДокумента;
		ТабличныйДокумент.Вывести(ШаблонСтрокаТабличныеДокументы);
		ТабличныйДокумент.Вывести(ШаблонПустаяСтрока);
		
		ВыводимыйДокумент = ЭлементСтруктуры.Значение.Данные;
		ОбластьВыводаТабличногоДокумента = ТабличныйДокумент.Вывести(ВыводимыйДокумент);
		ОбластьВыводаТабличногоДокумента.СоздатьФорматСтрок();
		
		Для НомерКолонки = 1 По ВыводимыйДокумент.ШиринаТаблицы Цикл 
			ШиринаКолонки = ВыводимыйДокумент.Область(1, НомерКолонки, ВыводимыйДокумент.ВысотаТаблицы, НомерКолонки).ШиринаКолонки;
			ТабличныйДокумент.Область(ОбластьВыводаТабличногоДокумента.Верх, НомерКолонки,
				ОбластьВыводаТабличногоДокумента.Низ, НомерКолонки).ШиринаКолонки = ШиринаКолонки;
		КонецЦикла;
		
		ТабличныйДокумент.Вывести(ШаблонПустаяСтрока);
	КонецЦикла;
	
	ТабличныйДокумент.ЗакончитьГруппуСтрок();
	ТабличныйДокумент.Вывести(ШаблонПустаяСтрока);
	
КонецПроцедуры

Функция НаименованиеВыводимогоРеквизита(СсылкаНаОбъект, Знач ИмяРеквизита) Экспорт
	
	ВыводитьРеквизит = Истина;
	
	ОписаниеРеквизита = МетаданныеРеквизита(СсылкаНаОбъект.Метаданные(), ИмяРеквизита);
	Если ОписаниеРеквизита = Неопределено Тогда
		ОписаниеРеквизита = Метаданные.ОбщиеРеквизиты.Найти(ИмяРеквизита);
	КонецЕсли;
	
	ПредставлениеРеквизита = ИмяРеквизита;
	Если ОписаниеРеквизита <> Неопределено Тогда
		ПредставлениеРеквизита = ОписаниеРеквизита.Представление();
	КонецЕсли;
	
	ВерсионированиеОбъектовПереопределяемый.ПриОпределенииНаименованияРеквизитаОбъекта(СсылкаНаОбъект, 
		ИмяРеквизита, ПредставлениеРеквизита, ВыводитьРеквизит);
	
	Возврат Новый Структура("ВыводимоеНаименование, ВыводитьРеквизит, ОписаниеРеквизита", 
		ПредставлениеРеквизита, ВыводитьРеквизит, ОписаниеРеквизита);
	
КонецФункции

Функция ДанныеДляХранения(Знач Объект)
	
	СсылкаНаОбъект = Объект;
	Если ОбщегоНазначения.ЗначениеСсылочногоТипа(Объект) Тогда
		Объект = Объект.ПолучитьОбъект();
	Иначе
		СсылкаНаОбъект = Объект.Ссылка;
	КонецЕсли;
	
	ДанныеОбъекта = СериализоватьОбъект(Объект);
	
	ТабличныеДокументы = ТабличныеДокументыОбъекта(СсылкаНаОбъект);
	
	ДополнительныеРеквизиты = КоллекцияДополнительныхРеквизитов();
	СкрываемыеРеквизиты = КоллекцияСкрываемыхРеквизитов();
	
	ВерсионированиеОбъектовПереопределяемый.ПриПодготовкеДанныхОбъекта(Объект, ДополнительныеРеквизиты);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
		МодульУправлениеСвойствамиСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствамиСлужебный");
		МодульУправлениеСвойствамиСлужебный.ПриПодготовкеДанныхОбъекта(Объект, ДополнительныеРеквизиты);
		СкрываемыеРеквизиты.Добавить("ДополнительныеРеквизиты.*");
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформациейСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформациейСлужебный");
		МодульУправлениеКонтактнойИнформациейСлужебный.ПриПодготовкеДанныхОбъекта(Объект, ДополнительныеРеквизиты);
		СкрываемыеРеквизиты.Добавить("КонтактнаяИнформация.*");
	КонецЕсли;
	
	МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоСсылке(СсылкаНаОбъект);
	Настройки = НастройкиПодсистемы();
	Попытка
		МенеджерОбъекта.ПриОпределенииНастроекВерсионированияОбъектов(Настройки);
	Исключение
		Настройки = НастройкиПодсистемы();
	КонецПопытки;
	
	СлужебныеРеквизитыОбъекта = Новый Массив;
	Если Настройки.ПриПолученииСлужебныхРеквизитов Тогда
		МенеджерОбъекта.ПриПолученииСлужебныхРеквизитов(СлужебныеРеквизитыОбъекта);
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(СкрываемыеРеквизиты, СлужебныеРеквизитыОбъекта);
	КонецЕсли;
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(СкрываемыеРеквизиты, СлужебныеРеквизитыОбъектов());
	
	Результат = Новый Структура;
	
	Если ТабличныеДокументы <> Неопределено И ТабличныеДокументы.Количество() > 0 Тогда
		Результат.Вставить("ТабличныеДокументы", ТабличныеДокументы);
	КонецЕсли;
	
	Если ДополнительныеРеквизиты.Количество() > 0 Тогда
		Результат.Вставить("ДополнительныеРеквизиты", ДополнительныеРеквизиты);
	КонецЕсли;
	
	Если СкрываемыеРеквизиты.Количество() > 0 Тогда
		Результат.Вставить("СкрываемыеРеквизиты", СкрываемыеРеквизиты);
	КонецЕсли;
	
	Если Результат.Количество() > 0 Тогда
		Результат.Вставить("Объект", ДанныеОбъекта);
	Иначе
		Результат = ДанныеОбъекта;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция КоллекцияДополнительныхРеквизитов()
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Идентификатор");
	Результат.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("Значение");
	
	Возврат Результат;
КонецФункции

Функция КоллекцияСкрываемыхРеквизитов()
	Возврат Новый Массив;
КонецФункции

// Возвращаемое значение:
//   Массив из Структура:
//   * Значение - Структура:
//   ** Наименование - Строка
//
Функция ТабличныеДокументыОбъекта(Ссылка) Экспорт
	Результат = Новый Структура;
	ВерсионированиеОбъектовПереопределяемый.ПриПолученииТабличныхДокументовОбъекта(Ссылка, Результат);
	Возврат Результат;
КонецФункции

Функция СлужебныеРеквизитыОбъектов()
	Реквизиты = Новый Массив;
	Реквизиты.Добавить("Ref");
	Реквизиты.Добавить("IsFolder");
	Реквизиты.Добавить("PredefinedDataName");
	
	Возврат Реквизиты;
КонецФункции

Функция РазмерДанных(Данные) Экспорт
	Возврат Base64Значение(СериализаторXDTO.XMLСтрока(Данные)).Размер();
КонецФункции

Процедура ДобавитьИнформациюОбУзле(Запись, Получатель)
	
	Если Запись.Узел = ОбщегоНазначения.ПредметСтрокой(Получатель.Ссылка) Тогда
		Запись.Узел = "";
	Иначе
		Если ПустаяСтрока(Запись.Узел) Тогда
			ПланОбменаМенеджер = ОбщегоНазначения.МенеджерОбъектаПоСсылке(Получатель.Ссылка);
			Запись.Узел = ОбщегоНазначения.ПредметСтрокой(ПланОбменаМенеджер.ЭтотУзел());
		КонецЕсли;
	КонецЕсли;
	
	Если Запись.АвторВерсии = Неопределено Тогда
		Возврат;
	КонецЕсли;
	МетаданныеАвтора = Запись.АвторВерсии.Метаданные();
	Если ОбщегоНазначения.ЭтоПланОбмена(МетаданныеАвтора) Тогда
		
		Запись.ПредупреждениеСинхронизации = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("<АвторВерсии>%1;%2</АвторВерсии>",
			МетаданныеАвтора.Имя, ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Запись.АвторВерсии, "Код"))
			+ Запись.ПредупреждениеСинхронизации;
			
	КонецЕсли;
	
КонецПроцедуры

Процедура ПрочитатьИнформациюОбУзле(Запись)
	
	Если СтрНачинаетсяС(Запись.Комментарий, "<АвторВерсии>") Тогда
		Позиция = СтрНайти(Запись.Комментарий, "</АвторВерсии>");
		Если Позиция > 0 Тогда
			ОписаниеУзла = Лев(Запись.Комментарий, Позиция - 1);
			Запись.Комментарий = Сред(Запись.Комментарий, Позиция + СтрДлина("</АвторВерсии>"));
			ОписаниеУзла = Сред(ОписаниеУзла, СтрДлина("<АвторВерсии>") + 1);
			ОписаниеУзла = СтрРазделить(ОписаниеУзла, ";");
			ИмяУзла = ОписаниеУзла[0];
			КодУзла = ОписаниеУзла[1];
			АвторВерсии = ПланыОбмена[ИмяУзла].НайтиПоКоду(КодУзла);
			Если ЗначениеЗаполнено(АвторВерсии) Тогда
				Запись.АвторВерсии = АвторВерсии;
			КонецЕсли;
		КонецЕсли;
		
	ИначеЕсли СтрНачинаетсяС(Запись.ПредупреждениеСинхронизации, "<АвторВерсии>") Тогда
		
		Позиция = СтрНайти(Запись.ПредупреждениеСинхронизации, "</АвторВерсии>");
		Если Позиция > 0 Тогда
			ОписаниеУзла = Лев(Запись.ПредупреждениеСинхронизации, Позиция - 1);
			Запись.ПредупреждениеСинхронизации = Сред(Запись.ПредупреждениеСинхронизации, Позиция + СтрДлина("</АвторВерсии>"));
			ОписаниеУзла = Сред(ОписаниеУзла, СтрДлина("<АвторВерсии>") + 1);
			ОписаниеУзла = СтрРазделить(ОписаниеУзла, ";");
			ИмяУзла = ОписаниеУзла[0];
			КодУзла = ОписаниеУзла[1];
			АвторВерсии = ПланыОбмена[ИмяУзла].НайтиПоКоду(КодУзла);
			Если ЗначениеЗаполнено(АвторВерсии) Тогда
				Запись.АвторВерсии = АвторВерсии;
			КонецЕсли;
		КонецЕсли;
	
	КонецЕсли;
	
	Если Запись.АвторВерсии = Неопределено Тогда
		Возврат;
	КонецЕсли;
	МетаданныеАвтора = Запись.АвторВерсии.Метаданные();
	
	Если ОбщегоНазначения.ЭтоПланОбмена(МетаданныеАвтора) Тогда
		ПланОбменаМенеджер = ОбщегоНазначения.МенеджерОбъектаПоСсылке(Запись.АвторВерсии);
		Если Запись.АвторВерсии = ПланОбменаМенеджер.ЭтотУзел() Тогда
			Запись.Узел = "";
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

Функция ВерсииКВыгрузке(Объект, Узел)
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ВерсииОбъектовИзменения.НомерВерсии КАК НомерВерсии
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов.Изменения КАК ВерсииОбъектовИзменения
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|		ПО ВерсииОбъектовИзменения.Объект = ВерсииОбъектов.Объект
	|			И ВерсииОбъектовИзменения.НомерВерсии = ВерсииОбъектов.НомерВерсии
	|ГДЕ
	|	ВерсииОбъектовИзменения.Объект = &Объект
	|	И ВерсииОбъектовИзменения.Узел = &Узел
	|
	|УПОРЯДОЧИТЬ ПО
	|	НомерВерсии УБЫВ";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Объект", Объект);
	Запрос.УстановитьПараметр("Узел", Узел);
	
	Возврат Запрос.Выполнить().Выгрузить();
	
КонецФункции

Функция НастройкиПодсистемы()
	Результат = Новый Структура;
	Результат.Вставить("ПриПолученииСлужебныхРеквизитов", Ложь);
	
	Возврат Результат;
КонецФункции

Функция КоличествоНесинхронизируемыхВерсий(Объект, НомерВерсии)
	
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	КОЛИЧЕСТВО(1) КАК Количество
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	НЕ ВерсииОбъектов.Синхронизируется
	|	И ВерсииОбъектов.Объект = &Объект
	|	И ВерсииОбъектов.НомерВерсии < &НомерВерсии";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Объект", Объект);
	Запрос.УстановитьПараметр("НомерВерсии", НомерВерсии);
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		Возврат Выборка.Количество;
	КонецЕсли;
	
	Возврат 0;
	
КонецФункции

Функция ВыполняетсяЗаписьОбъекта(Значение = Неопределено)
	Если Значение <> Неопределено Тогда
		ПараметрыСеанса.ВыполняетсяЗаписьОбъекта = Значение;
		Возврат Значение;
	КонецЕсли;
	Возврат ПараметрыСеанса.ВыполняетсяЗаписьОбъекта;
КонецФункции

Функция РегистрВерсийВходитВСоставПланаОбмена(Отправитель)
	ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Отправитель));
	Возврат ОбъектМетаданных.Состав.Содержит(Метаданные.РегистрыСведений.ВерсииОбъектов);
КонецФункции

Функция ПерейтиНаВерсиюСервер(Ссылка, НомерВерсии, ТекстСообщенияОбОшибке, ОтменаПроведения = Ложь) Экспорт
	
	Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
		ВызватьИсключение НСтр("ru = 'Недостаточно прав для выполнения операции.'");
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ВерсииОбъектов");
	ЭлементБлокировки.УстановитьЗначение("Объект", Ссылка);
	
	ЭлементБлокировки = Блокировка.Добавить(Ссылка.Метаданные().ПолноеИмя());
	ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка);
	
	ИдентификаторОшибки = "ОшибкаВосстановления";
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		ЗаблокироватьДанныеДляРедактирования(Ссылка);
		
		ПользовательскоеПредставлениеНомера = НомерВерсииВИерархии(Ссылка, НомерВерсии);
		Информация = СведенияОВерсииОбъекта(Ссылка, НомерВерсии);
		
		ДополнительныеРеквизиты = Неопределено;
		Если ТипЗнч(Информация.ВерсияОбъекта) = Тип("Структура") Тогда
			Если Информация.ВерсияОбъекта.Свойство("ДополнительныеРеквизиты", ДополнительныеРеквизиты) Тогда
				НайденныеРеквизиты = ДополнительныеРеквизиты.НайтиСтроки(Новый Структура("Идентификатор", Неопределено));
				Для Каждого Реквизит Из НайденныеРеквизиты Цикл
					ДополнительныеРеквизиты.Удалить(Реквизит);
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
	
		ТекстСообщенияОбОшибке = "";
		Объект = ВосстановитьОбъектПоXML(Информация.ВерсияОбъекта, ТекстСообщенияОбОшибке);
		
		Если Не ПустаяСтрока(ТекстСообщенияОбОшибке) Тогда
			ОтменитьТранзакцию();
			Возврат "ОшибкаВосстановления";
		КонецЕсли;
	
		Объект.ДополнительныеСвойства.Вставить("ВерсионированиеОбъектовКомментарийКВерсии",
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Выполнен переход к версии №%1 от %2'"),
				ПользовательскоеПредставлениеНомера,
				Формат(Информация.ДатаВерсии, "ДЛФ=DT")));
	
		РежимЗаписи = Неопределено;
	
		Если ОбщегоНазначения.ЭтоДокумент(Объект.Метаданные()) И Объект.Метаданные().Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
			Если Объект.Проведен И Не ОтменаПроведения Тогда
				РежимЗаписи = РежимЗаписиДокумента.Проведение;
			ИначеЕсли Не Объект.Ссылка.Пустая() Тогда
				РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения;
			КонецЕсли;
			ИдентификаторОшибки = "ОшибкаПроведения";
		КонецЕсли;
		
		Если Ссылка.ПолучитьОбъект() <> Неопределено Тогда
			ЗаписатьДанныеТекущейВерсии(Ссылка);
		КонецЕсли;
		
		ВыполняетсяЗаписьОбъекта(Истина);
		Если ЗначениеЗаполнено(РежимЗаписи) Тогда
			Объект.Записать(РежимЗаписи);
		Иначе
			Объект.Записать();
		КонецЕсли;
		Если ЗначениеЗаполнено(ДополнительныеРеквизиты) Тогда
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
				МодульУправлениеСвойствамиСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствамиСлужебный");
				МодульУправлениеСвойствамиСлужебный.ПриВосстановленииВерсииОбъекта(Объект, ДополнительныеРеквизиты);
			КонецЕсли;
			ВерсионированиеОбъектовПереопределяемый.ПриВосстановленииВерсииОбъекта(Объект, ДополнительныеРеквизиты);
		КонецЕсли;
		ВыполняетсяЗаписьОбъекта(Ложь);
		
		ЗаписатьВерсиюОбъекта(Объект);
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВыполняетсяЗаписьОбъекта(Ложь);
		ТекстСообщенияОбОшибке = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		Возврат ИдентификаторОшибки;
	КонецПопытки;
	
	Возврат "ВосстановлениеВыполнено";
	
КонецФункции

Функция НомерВерсииВИерархии(Ссылка, НомерВерсии)
	
	Если ЕстьПравоЧтенияДанныхВерсийОбъектов() Тогда
		УстановитьПривилегированныйРежим(Истина);
	КонецЕсли;
	
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	ВерсииОбъектов.НомерВерсии КАК НомерВерсии,
	|	ВерсииОбъектов.ВерсияВладелец
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.Объект = &Ссылка
	|
	|УПОРЯДОЧИТЬ ПО
	|	НомерВерсии УБЫВ";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	
	ТаблицаВерсий = Запрос.Выполнить().Выгрузить();
	
	ДеревоВерсий = Новый ДеревоЗначений;
	ДеревоВерсий.Колонки.Добавить("НомерВерсии");
	ДеревоВерсий.Колонки.Добавить("ПредставлениеНомераВерсии");
	ДеревоВерсий.Колонки.Добавить("Отклонена", Новый ОписаниеТипов("Булево"));
	
	ЗаполнитьИерархиюВерсий(ДеревоВерсий, ТаблицаВерсий);
	ПронумероватьВерсии(ДеревоВерсий.Строки);
	
	ОписаниеВерсии = ДеревоВерсий.Строки.Найти(НомерВерсии, "НомерВерсии", Истина);
	Результат = ОписаниеВерсии;
	Если Результат <> Неопределено Тогда
		Результат = ОписаниеВерсии.ПредставлениеНомераВерсии;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Процедура ЗаполнитьИерархиюВерсий(ИерархияВерсий, СписокВерсий) Экспорт
	
	ПропущенныеВерсии = Новый Массив;
	Для Каждого ОписаниеВерсии Из СписокВерсий Цикл
		Если ОписаниеВерсии.ВерсияВладелец = 0 Тогда
			Элемент = ИерархияВерсий.Строки.Добавить();
		Иначе
			НайденнаяВерсия = ИерархияВерсий.Строки.Найти(ОписаниеВерсии.ВерсияВладелец, "НомерВерсии", Истина);
			Если НайденнаяВерсия <> Неопределено Тогда
				Элемент = НайденнаяВерсия.Строки.Добавить();
				НайденнаяВерсия.Отклонена = Истина;
			Иначе
				ПропущенныеВерсии.Добавить(ОписаниеВерсии);
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		ЗаполнитьЗначенияСвойств(Элемент, ОписаниеВерсии);
	КонецЦикла;
	
	Если ПропущенныеВерсии.Количество() > 0 Тогда
		Если СписокВерсий.Количество() = ПропущенныеВерсии.Количество() Тогда
			Возврат;
		КонецЕсли;
		ЗаполнитьИерархиюВерсий(ИерархияВерсий, ПропущенныеВерсии);
	КонецЕсли;
	
КонецПроцедуры

Процедура ПронумероватьВерсии(КоллекцияВерсий) Экспорт
	
	ТекущийНомерВерсии = КоллекцияВерсий.Количество();
	Для Каждого Версия Из КоллекцияВерсий Цикл
		ПрефиксНомера = "";
		Если Версия.Родитель <> Неопределено И Не ПустаяСтрока(Версия.Родитель.ПредставлениеНомераВерсии) Тогда
			ПрефиксНомера = Версия.Родитель.ПредставлениеНомераВерсии + ".";
		КонецЕсли;
		
		Версия.ПредставлениеНомераВерсии = ПрефиксНомера + Формат(ТекущийНомерВерсии, "ЧГ=0");
		ПронумероватьВерсии(Версия.Строки);
		ТекущийНомерВерсии = ТекущийНомерВерсии - 1;
	КонецЦикла;
	
КонецПроцедуры

Функция НомерВерсииВРегистре(Объект, ПорядковыйНомерСинхронизируемойВерсии)
	
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	ВерсииОбъектов.НомерВерсии КАК НомерВерсии,
	|	ВерсииОбъектов.Синхронизируется КАК Синхронизируется
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.Объект = &Объект
	|
	|УПОРЯДОЧИТЬ ПО
	|	НомерВерсии";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Объект", Объект);
	ВерсииОбъектов = Запрос.Выполнить().Выгрузить();
	ВерсииОбъектов.Индексы.Добавить("Синхронизируется");
	
	Синхронизируемые = ВерсииОбъектов.НайтиСтроки(Новый Структура("Синхронизируется", Истина));
	НеСинхронизируемые = ВерсииОбъектов.НайтиСтроки(Новый Структура("Синхронизируется", Ложь));
	
	Если Синхронизируемые.Количество() >= ПорядковыйНомерСинхронизируемойВерсии Тогда
		Возврат Синхронизируемые[ПорядковыйНомерСинхронизируемойВерсии - 1].НомерВерсии;
	КонецЕсли;
	
	Возврат НеСинхронизируемые.Количество() + ПорядковыйНомерСинхронизируемойВерсии;
	
КонецФункции

Процедура СоздатьВерсиюВладельцаНепринятых(НомерПоследнейОтклоненнойВерсии, НомерВерсииСКоллизией, Объект, АвторВерсии)
	
	НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.Объект.Установить(Объект);
	НаборЗаписей.Отбор.НомерВерсии.Установить(НомерВерсииСКоллизией);
	Запись = НаборЗаписей.Добавить();
	
	ПоследняяВерсияКВыгрузке = РегистрыСведений.ВерсииОбъектов.СоздатьМенеджерЗаписи();
	ПоследняяВерсияКВыгрузке.Объект = Объект;
	ПоследняяВерсияКВыгрузке.НомерВерсии = НомерПоследнейОтклоненнойВерсии;
	ПоследняяВерсияКВыгрузке.Прочитать();
	
	ЗаполнитьЗначенияСвойств(Запись, ПоследняяВерсияКВыгрузке, , "ВерсияВладелец");
	Запись.НомерВерсии = НомерВерсииСКоллизией;
	Запись.ДатаВерсии = ТекущаяДатаСеанса();
	Запись.ПредупреждениеСинхронизации = НСтр("ru = 'Отклоненная версия (автоматическое разрешение конфликта).'");
	Запись.АвторВерсии = АвторВерсии;
	
	Если Не Запись.ЕстьДанныеВерсии Тогда
		Запись.ВерсияОбъекта = Новый ХранилищеЗначения(ДанныеДляХранения(Запись.Объект), Новый СжатиеДанных(9))
	КонецЕсли;
	НаборЗаписей.Записать();

КонецПроцедуры

// Для вызова из ПриПолученииДанныхОтГлавного и ПриПолученииДанныхОтПодчиненного.
//
// Параметры:
//   Отправитель
//
Процедура ЗаписатьВерсиюСИзменениемНомера(ЭлементДанных, ПолучениеЭлемента, Отправитель, НомерВерсии)
	
	Объект = ЭлементДанных.Отбор.Объект.Значение;
	
	НаборЗаписей = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.Объект.Установить(Объект);
	НаборЗаписей.Отбор.НомерВерсии.Установить(НомерВерсии);
	НаборЗаписей.Прочитать();
	
	Если НаборЗаписей.Количество() = 0 Тогда
		Запись = НаборЗаписей.Добавить();
		Запись.Объект = Объект;
		Запись.НомерВерсии = НомерВерсии;
	Иначе
		Запись = НаборЗаписей[0];
	КонецЕсли;
	ЗаполнитьЗначенияСвойств(Запись, ЭлементДанных[0], , "Объект,НомерВерсии");
	НаборЗаписей.Записать(); // АПК:1327 блокировка не требуется, так как процедура вызывается в транзакции с уже установленной блокировкой.
	
	ПланыОбмена.УдалитьРегистрациюИзменений(Отправитель.Ссылка, НаборЗаписей);
	ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
	
КонецПроцедуры

#КонецОбласти
